目录
21. 数组中出现次数超过一半的数字(哈希Map记录出现次数)
22. 数组中只出现一次的两个数字(哈希Map记录出现次数)
1. 两数之和(Hashmap)
class Solution:
def twoSum(self , numbers: List[int], target: int) -> List[int]:
res = []
map = dict()
for i in range(len(numbers)):
tmp = target - numbers[i]
if tmp not in map:
map[numbers[i]] = i
else:
res.append(map[tmp] + 1)
res.append(i + 1)
break
return res
2. 三数之和(三指针法)
(i、left、right三个指针)i 当作第一个值遍历数组,left 和 right 前后指针遍历查找
class Solution:
def threeSum(self , num: List[int]) -> List[List[int]]:
res = []
if len(num) < 3: return res
num.sort()
# i 从 0 下标到 len-3
for i in range(len(num)-2):
# 避免首元素重复
if i > 0 and num[i] == num[i-1]:
continue
l = i + 1
r = len(num) - 1
while l < r:
if num[i] + num[l] + num[r] < 0:
l += 1
elif num[i] + num[l] + num[r] > 0:
r -= 1
else:
res.append([num[i], num[l], num[r]])
while l+1 < r and num[l] == num[l+1]:
l += 1
while l+1 < r and num[r] == num[r-1]:
r -= 1
l += 1
r -= 1
return res
3. 第 k 个缺失的正整数
大数组存储:空间换时间方法O(n)
class Solution:
def findKthPositive(self, arr: List[int], k: int) -> int:
nums = [-1]*(arr[-1]+k)
for a in arr:
nums[a-1] = 0
count = 0
for i in range(len(nums)):
if nums[i] != 0:
count += 1
if count == k:
return i+1
set记录已出现的数据O(n)
class Solution:
def findKthPositive(self, arr: List[int], k: int) -> int:
sets = set()
count = 0
for a in arr:
sets.add(a)
for i in range(1, arr[-1]+1):
if i not in sets:
count += 1
if count == k:
return i
return arr[-1]-count+k
二分查找O(logn)
class Solution:
def findKthPositive(self, arr: List[int], k: int) -> int:
l = 0
r = len(arr) - 1
# 当第一个数大于k时,说明第k个缺失的值就是k
if arr[0] > k:
return k
while l < r:
mid = (l+r)//2
if arr[mid] - (mid+1) >= k:
r = mid
else:
l = mid + 1
if arr[r] - (r + 1) >= k:
return r + k
else:
return r + k + 1
4. 连续子数组的最大和(DP)
class Solution:
def FindGreatestSumOfSubArray(self, array: List[int]) -> int:
# 记录到下标i为止的最大连续子数组和
dp = [0 for i in range(len(array))]
dp[0] = array[0]
maxsum = dp[0]
for i in range(1, len(array)):
# 状态转移:连续子数组和最大值
dp[i] = max(dp[i - 1] + array[i], array[i])
# 维护最大值
maxsum = max(maxsum, dp[i])
return maxsum
5. 最长无重复子数组(滑动窗口)
class Solution:
def maxLength(self , arr: List[int]) -> int:
map = dict()
res = 0
left = 0
for right in range(len(arr)):
if arr[right] in map:
map[arr[right]] += 1
else:
map[arr[right]] = 1
# 窗口内有重复则窗口左侧移动
while map[arr[right]] > 1:
map[arr[left]] -= 1
left += 1
res = max(res, right - left + 1)
return res
6. 滑动窗口的最大值
class Solution:
def maxInWindows(self , num: List[int], size: int) -> List[int]:
res = []
if size <= 0 or size > len(num): return res
for i in range(len(num) - size + 1):
# 寻找每个窗口的最大值
maxx = 0
for j in range(i, i + size):
maxx = max(maxx, num[j])
res.append(maxx)
return res
双向队列
from collections import deque
class Solution:
def maxInWindows(self , num: List[int], size: int) -> List[int]:
res = []
if size <= 0 or size > len(num): return res
# 双向队列
dq = deque()
# 遍历第一个窗口
for i in range(size):
# 去掉小值
while len(dq) != 0 and num[dq[-1]] < num[i]:
dq.pop()
dq.append(i)
# 遍历后续数组
for i in range(size, len(num)):
res.append(num[dq[0]])
# 移除上一个窗口中的值
while len(dq) != 0 and dq[0] < (i - size + 1):
dq.popleft()
# 去掉小值
while len(dq) != 0 and num[dq[-1]] < num[i]:
dq.pop()
dq.append(i)
res.append(num[dq[0]])
return res
7. 盛水最多的容器(双指针)
class Solution:
def maxArea(self , height: List[int]) -> int:
if len(height) < 2: return 0
res = 0
left = 0
right = len(height) - 1
while left < right:
capacity = min(height[left], height[right]) * (right - left)
res = max(res, capacity)
if height[left] < height[right]:
left += 1
else:
right -= 1
return res
8. 接雨水问题(双指针)
class Solution:
def maxWater(self , arr: List[int]) -> int:
res = 0
if len(arr) == 0: return res
left = 0
right = len(arr) - 1
maxL = 0
maxR = 0
while left < right:
maxL = max(maxL, arr[left])
maxR = max(maxR, arr[right])
# 按较短边界积水,并移动指针
if maxL < maxR:
res += maxL - arr[left]
left += 1
else:
res += maxR - arr[right]
right -= 1
return res
9. 合并两个有序数组
class Solution:
def merge(self , A, m, B, n):
a = m-1
b = n-1
for i in range(m+n-1, -1, -1):
if b < 0 or a >= 0 and A[a]>=B[b]:
A[i] = A[a]
a -= 1
else:
A[i] = B[b]
b -= 1
return A
10. 合并区间 力扣(LeetCode)
入参为单链表:
def merge(nums):
if len(nums) <= 1: return nums
res = []
now = nums[0]
cur = now
for i in range(1, len(nums)):
if nums[i] == cur + 1:
cur += 1
continue
elif now == cur:
res.append(str(now))
else:
res.append(str(now) + '->' + str(cur))
now = nums[i]
cur = now
if nums[-1] == nums[-2]+1:
res.append(str(now) + '->' + str(cur))
else:
res.append(str(nums[-1]))
return res
nums1 = [0,1,2,4,5,7]
nums2 = [0,2,3,4,6,8,9]
nums3 = []
nums4 = [-1]
nums5 = [0]
print(merge(nums))
入参为嵌套链表:
class Solution:
def merge(self, intervals: List[List[int]]) -> List[List[int]]:
intervals.sort(key = lambda x: x[0])
res = []
res.append(intervals[0])
for i in range(len(intervals)):
if res[-1][-1] < intervals[i][0]:
res.append(intervals[i])
else:
res[-1][-1] = max(res[-1][-1], intervals[i][-1])
return res
11. 两个数组的交集
两个set去重:
class Solution:
def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]:
set1 = set(nums1)
set2 = set(nums2)
res = []
for i in set1:
if i in set2:
res.append(i)
return res
排序+双指针:
class Solution:
def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]:
nums1.sort()
nums2.sort()
# 指针
p1, p2 = 0, 0
res = []
while p1 < len(nums1) and p2 < len(nums2):
if nums1[p1] == nums2[p2]:
if res == [] or nums1[p1] != res[-1]:
res.append(nums1[p1])
p1 += 1
p2 += 1
elif nums1[p1] < nums2[p2]:
p1 += 1
else:
p2 += 1
return res
用两个集合去重:
class Solution:
def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]:
set1 = set(nums1)
set2 = set(nums2)
return self.set_intersection(set1, set2)
def set_intersection(self, set1, set2):
if len(set1) > len(set2):
return self.set_intersection(set2, set1)
return [x for x in set1 if x in set2]
12. 寻找两个正序数组的中位数
class Solution:
def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:
len1 = len(nums1)
len2 = len(nums2)
lens = len(nums1) + len(nums2)
l , r = 0, 0
p1, p2 = 0, 0
for _ in range(lens//2 + 1):
l = r
if p1 < len(nums1) and (p2 >= len(nums2) or nums1[p1] < nums2[p2]):
r = nums1[p1]
p1 += 1
else:
r = nums2[p2]
p2 += 1
return (l+r)/2 if lens%2 == 0 else r
13. 二分查找
class Solution:
def search(self , nums: List[int], target: int) -> int:
# 首尾指针,依次通过mid进行对比
l = 0
r = len(nums)-1
while l<=r:
mid = (l+r)//2
if nums[mid] < target:
l = mid + 1
elif nums[mid] > target:
r = mid - 1
else:
return mid
return -1
14. 旋转数组的最小数字(二分查找)
class Solution:
def minNumberInRotateArray(self , rotateArray: List[int]) -> int:
if len(rotateArray) == 0: return 0
i, j = 0, len(rotateArray)-1
# 不断缩小边界,找到最小值
while i < j:
m = (i+j)//2
if rotateArray[m] > rotateArray[j]:
i = m + 1
elif rotateArray[m] < rotateArray[j]:
j = m
else:
j -= 1
return rotateArray[i]
15. 二维数组中的查找(二分查找)
二层循环(暴力搜索):
class Solution:
def Find(self , target: int, array: List[List[int]]) -> bool:
for i in range(len(array)):
for j in range(len(array[0])):
if array[i][j] == target:
return True
return False
二分查找(分治思想):
class Solution:
def Find(self , target: int, array: List[List[int]]) -> bool:
if len(array) == 0 or len(array[0]) == 0: return False
n = len(array)
m = len(array[0])
# 从左下角开始搜索
i = n -1
j = 0
while i >= 0 and j < m:
if array[i][j] > target:
i -= 1
elif array[i][j] < target:
j += 1
else:
return True
return False
16. 寻找峰值(二分)
暴力搜索:
class Solution:
def findPeakElement(self , nums: List[int]) -> int:
# 首尾特殊情况
if len(nums) <= 1:
return 0
elif len(nums) == 2:
return 0 if nums[0] > nums[1] else 1
elif nums[0] >= nums[1]:
return 0
elif nums[len(nums)-1] > nums[len(nums)-2]:
return len(nums)-1
m = 1
while m <= len(nums)-2:
if nums[m-1] <= nums[m] and nums[m+1] <= nums[m]:
return m
m += 1
return -1
二分查找(分治思想):
class Solution:
def findPeakElement(self , nums: List[int]) -> int:
l = 0
r = len(nums) - 1
while l < r:
m = (l+r)//2
# 不断限制区间,m大则缩小右边界,m小则缩小左边界
if nums[m] > nums[m+1]:
r = m
else:
l = m + 1
# 当 l == r 时,即为一个峰
return r
17. 数组中的逆序对
class Solution:
def InversePairs(self , data: List[int]) -> int:
res = 0
for i in range(len(data)):
for j in range(i+1, len(data)):
if data[i] > data[j]:
res += 1
res %= 1000000007
return res
归并排序(分治)
class Solution:
def MergeSort(self, l: int, r: int, data: List[int], tmp: List[int]) -> int:
if l >= r:
return 0
m = (l+r)//2
res = self.MergeSort(l, m, data, tmp) + self.MergeSort(m + 1, r, data, tmp)
res %= 1000000007
i = l
j = m + 1
for n in range(l, r+1):
tmp[n] = data[n]
for n in range(l, r+1):
if i == m + 1:
data[n] = tmp[j]
j += 1
elif j == r + 1 or tmp[i] <= tmp[j]:
data[n] = tmp[i]
i += 1
else:
data[n] = tmp[j]
j += 1
# 统计逆序对
res += m -i + 1
return res%1000000007
def InversePairs(self , data: List[int]) -> int:
tmp = [0 for i in range(len(data))]
return self.MergeSort(0, len(data)-1, data, tmp)
18. 数组的全排列(递归)
class Solution:
def permute(self, nums: List[int]) -> List[List[int]]:
if len(nums) == 1: return [nums]
res = []
for i in range(len(nums)):
tmp = nums[:i] + nums[i+1:]
p = self.permute(tmp)
for x in p:
res.append([nums[i]]+x)
return res
回溯(深度优先遍历+状态重置)
class Solution:
def permute(self, nums: List[int]) -> List[List[int]]:
res = []
def backtrack(first = 0):
# 所有数都填完了
if first == len(nums):
res.append(nums[:])
for i in range(first, len(nums)):
# 动态维护数组
nums[first], nums[i] = nums[i], nums[first]
# 继续递归填下一个数
backtrack(first + 1)
# 撤销操作
nums[first], nums[i] = nums[i], nums[first]
backtrack()
return res
19. 没有重复项数字的全排列
class Solution:
# 递归
def recursion(self, res: List[List[int]], num: List[int], index: int):
# 分枝进入结尾,找到一种排列
if index == len(num) - 1:
res.append(num)
else:
# 遍历后续的元素
for i in range(index, len(num)):
# 交换
num[i], num[index] = num[index], num[i]
# 递归
self.recursion(res, num, index + 1)
# 回溯
num[i], num[index] = num[index], num[i]
def permute(self , num: List[int]) -> List[List[int]]:
num.sort()
res = list(list())
self.recursion(res, num, 0)
return res
20. 有重复项数字的全排列
class Solution:
def recursion(self, res: List[List[int]], num: List[int], tmp: List[int], vis: List[int]):
# 临时数组满了加入到结果集
if len(tmp) == len(num):
res.append(tmp.copy())
return
for i in range(len(num)):
if vis[i] == 1:
continue
if i > 0 and num[i - 1] == num[i] and not vis[i - 1]:
# 当前的元素num[i]与同一层的前一个元素num[i-1]相同num[i-1]已经用过了
continue
vis[i] = 1
tmp.append(num[i])
self.recursion(res, num, tmp, vis)
vis[i] = 0
tmp.pop()
def permuteUnique(self , num: List[int]) -> List[List[int]]:
num.sort()
# 标记每个元素是否被使用过
vis = [0]*len(num)
res = list(list())
tmp = list()
self.recursion(res, num, tmp, vis)
return res
21. 数组中出现次数超过一半的数字(哈希Map记录出现次数)
class Solution:
def MoreThanHalfNum_Solution(self , numbers: List[int]) -> int:
map = dict()
for i in range(len(numbers)):
if numbers[i] in map:
map[numbers[i]] += 1
else:
map[numbers[i]] = 1
if map[numbers[i]] > len(numbers)//2:
return numbers[i]
return 0
22. 数组中只出现一次的两个数字(哈希Map记录出现次数)
class Solution:
def FindNumsAppearOnce(self , array: List[int]) -> List[int]:
map = dict()
res = []
for i in range(len(array)):
if array[i] in map:
map[array[i]] += 1
else:
map[array[i]] = 1
# 再次遍历数组,找到频率为1的两个数
for i in range(len(array)):
if map[array[i]] == 1:
res.append(array[i])
res.sort()
return res
异或运算
class Solution:
def FindNumsAppearOnce(self , array: List[int]) -> List[int]:
res = [0, 0]
tmp = 0
for i in range(len(array)):
tmp ^= array[i]
k = 1
while k & tmp == 0:
k <<= 1
for i in range(len(array)):
if k & array[i] == 0:
res[0] ^= array[i]
else:
res[1] ^= array[i]
res.sort()
return res
23. 缺失的第一个正整数(哈希Map记录出现次数)
class Solution:
def minNumberDisappeared(self , nums: List[int]) -> int:
map = dict()
for i in range(len(nums)):
if nums[i] in map:
map[nums[i]] += 1
else:
map[nums[i]] = 1
res = 1
while res in map:
res += 1
return res