defleftMargin(): # 左边界 left, right = 0, len(nums) - 1 while left <= right: mid = (left + right) // 2 if nums[mid] < target: # ... Ture # False ... left = mid + 1 else: right = mid - 1 return left if nums[left] == target else -1# 越界检验
二分查找右边界 [第一个 True ]
1 2 3 4 5 6 7 8 9
defrightMargin(): # 右边界 left, right = 0, len(nums) - 1 while left <= right: mid = (left + right) // 2 if nums[mid] > target: # ... False # Ture ... right = mid - 1 else: left = mid + 1 return right if nums[right] == target else -1
找出数组中重复的数字。==在一个长度为 n
的数组 nums 里的所有数字都在 0~n-1
的范围内==。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。
哈希表 / Set、原地交换(空间0(1))
合理利用 val 和 key 的关系
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
classSolution: deffindRepeatNumber(self, nums: [int]) -> int: dic = set() for num in nums: if num in dic: return num dic.add(num) return -1 deffindRepeatNumber(self, nums: [int]) -> int: i = 0 while i < len(nums): if nums[i] == i: i += 1 continue if nums[nums[i]] == nums[i]: return nums[i] nums[nums[i]], nums[i] = nums[i], nums[nums[i]] return -1
统计一个数字在排序数组中出现的次数。
找到目标值「最后」出现的分割点,并「往前」进行统计
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
classSolution: defsearch(self, nums: List[int], target: int) -> int: left, right = 0, len(nums) - 1 # 求右边界 while left <= right: mid = (right + left) // 2 if nums[mid] > target: right = mid - 1 else: left = mid + 1 # 最后要检查 right 越界的情况 if right < 0or nums[right] != target: return0 ans = 0 while right >= 0and nums[right] == target : right -= 1 ans += 1 return ans
classSolution: defmissingNumber(self, nums: List[int]) -> int: i, j = 0, len(nums) - 1 while i <= j: m = (i + j) // 2 if nums[m] == m: i = m + 1 else: j = m - 1 return i
在一个 n * m
的二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个高效的函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
我们将矩阵逆时针旋转 45° ,并将其转化为图形式,发现其类似于
二叉搜索树
1 2 3 4 5 6 7 8 9 10 11
classSolution: deffindNumberIn2DArray(self, matrix: List[List[int]], target: int) -> bool: i, j = len(matrix) - 1, 0 while i >= 0and j < len(matrix[0]): if matrix[i][j] > target: i -= 1 elif matrix[i][j] < target: j += 1 else: returnTrue returnFalse
classSolution: defthreeSum(self, nums: List[int]) -> List[List[int]]: # 排序 + 双指针 + 去冲 n = len(nums) nums.sort() ans = [] for i inrange(n): if nums[i] > 0: # 剪枝加速 break if i > 0and nums[i] == nums[i-1]: continue left, right = i + 1, n - 1 while left < right: cur = nums[i] + nums[left] + nums[right] if cur == 0: ans.append([nums[i], nums[left], nums[right]]) while left < right and nums[right] == nums[right - 1]: right -= 1 right -= 1 while left < right and nums[left] == nums[left + 1]: left += 1 left += 1 elif cur > 0: right -= 1 else: left += 1 return ans
classSolution: defminSubArrayLen(self, target: int, nums: List[int]) -> int: # 【前缀和 + 二分查找 o(nlogn)】 ifsum(nums) < target: return0 n = len(nums) pre = list(accumulate([0] + nums)) # itertools.accumulate() ans = n + 1 for i inrange(n + 1): cur = target + pre[i] """ left = bisect.bisect_left(pre, cur) """ left = i + 1 right = n while left <= right: mid = (left + right) // 2 if pre[mid] < cur: left = mid + 1 else: right = mid - 1 if left != n+1: ans = min(ans, left - i) return ans defminSubArrayLen(self, target: int, nums: List[int]) -> int: ifsum(nums) < target: return0 cur, res = 0, len(nums) + 1 i = 0 for j, var inenumerate(nums): cur += var while i <= j and cur >= target: if (t:= j - i + 1) < res: res = t cur -= nums[i] i += 1 return res
classSolution: defnumSubarrayProductLessThanK(self, nums: List[int], k: int) -> int: # 前缀和单调 + 二分查找 if k == 0: return0 k = math.log(k) pre = [0] for num in nums: pre.append(pre[-1] + math.log(num)) cur = res = 0 for i inrange(1, len(pre)): cur = k + pre[i - 1] j = bisect.bisect_left(pre, cur, lo = i) res += j - i return res defnumSubarrayProductLessThanK(self, nums: List[int], k: int) -> int: # 滑动窗口 n = len(nums) left, right = 0, n - 1 res = 0 i, cur =0, 1 for j, num inenumerate(nums): cur *= num while i <= j and cur >= k: # 左跟着右 cur //= nums[i] i += 1 res += j - i + 1 return res
狒狒喜欢吃香蕉。这里有 n 堆香蕉,第 i 堆中有 piles[i]
根香蕉。警卫已经离开了,将在 h
小时后回来。狒狒可以决定她吃香蕉的速度 k
(单位:根/小时)。每个小时,她将会选择一堆香蕉,从中吃掉 k
根。如果这堆香蕉少于 k
根,她将吃掉这堆的所有香蕉,然后这一小时内不会再吃更多的香蕉,下一个小时才会开始吃另一堆的香蕉。返回她可以在
h 小时内吃掉所有香蕉的最小速度 k(k 为整数)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
classSolution: defminEatingSpeed(self, piles: List[int], h: int) -> int: left, right = max(1, sum(piles) // h), max(piles) defcheck(k): count = 0 for pile in piles: count += ceil(pile / k) return count > h while left <= right: mid = (left + right) // 2 if check(mid): # ... Ture # False(r) ... left = mid + 1 else: right = mid - 1 return left
给你一个 n x n 矩阵 matrix
,其中每行和每列元素均按升序排序,找到矩阵中第
k 小的元素。 请注意,它是 排序后 的第 k 小元素,而不是第 k 个
不同 的元素。
classSolution: defkthSmallest(self, matrix: List[List[int]], k: int) -> int: # 优先队列 n = len(matrix) heap = [(matrix[i][0], i, 0) for i inrange(n)] heapq.heapify(heap) res = 0 for i inrange(k - 1): num, x, y = heapq.heappop(heap) if y != n - 1: heapq.heappush(heap, (matrix[x][y + 1], x, y + 1)) return heap[0][0] defkthSmallest(self, matrix: List[List[int]], k: int) -> int: # 二分查找 n = len(matrix) defcheck(mid): i, j = n - 1, 0 num = 0 while i >= 0and j < n: if matrix[i][j] <= mid: num += i + 1 j += 1 else: i -= 1 return num < k # 【第一个False】 left, right = matrix[0][0], matrix[-1][-1] while left <= right: mid = (left + right) // 2 if check(mid): left = mid + 1 else: right = mid - 1 return left