defmajorityElementRec(self,nums, l, r): if l == r : return nums[l] mid = (l+r)//2 left = self.majorityElementRec(nums,l,mid) right = self.majorityElementRec(nums,mid+1,r)
if (left == right): return left leftCount = sum(1for i inrange(l, r+1) if nums[i] == left) rightCount = sum(1for i inrange(l, r+1) if nums[i] == right) return left if leftCount > rightCount else right
classSolution: deflargestRectangleArea(self, heights: List[int]) -> int: n = len(heights) left = [-1] * n st = [] for i , x inenumerate(heights): while st and x<= heights[st[-1]]: st.pop() if st: left[i] = st[-1] st.append(i) right = [n] * n st.clear() for i inrange(n - 1, -1, -1): x = heights[i] while st and x <= heights[st[-1]]: st.pop() if st: right[i] = st[-1] st.append(i)
ans = 0 for h, l, r inzip(heights, left, right): ans = max(ans, h * (r - l - 1)) return ans
优化一下本题代码,因为我们没有必要把左右边界都搜索一遍
1 2 3 4 5 6 7 8 9 10 11 12 13
classSolution: deflargestRectangleArea(self, heights: List[int]) -> int: r = [0] st = [] heights = [0] + heights + [0] for i, h inenumerate(heights): while st and h < heights[st[-1]]: a = st.pop() if st: hi = heights[a] r.append((i - st[-1] - 1) * (hi)) st.append(i) returnmax(r)
classSolution: deflargestRectangleArea(self, heights: List[int]) -> int: r = [0] st = [] heights = [0] + heights + [0] for i, h inenumerate(heights): while st and h < heights[st[-1]]: a = st.pop() if st: hi = heights[a] r.append((i - st[-1] - 1) * (hi)) st.append(i) returnmax(r)
defmaximalRectangle(self, matrix: List[List[str]]) -> int: m,n=len(matrix),len(matrix[0]) heights = [0]*n ans = 0 for row in matrix: for i,c inenumerate(row): heights[i]=0if c=='0'else heights[i]+1 if self.largestRectangleArea(heights)>ans: ans = self.largestRectangleArea(heights) return ans
739. 每日温度
1 2 3 4 5 6 7 8 9 10 11 12 13
classSolution: defdailyTemperatures(self, temperatures: List[int]) -> List[int]: n = len(temperatures) right = [0]*n st = [] for i inrange(n-1,-1,-1): while st and temperatures[i]>= temperatures[st[-1]]: st.pop() if st: right[i] = st[-1] - i st.append(i)
classSolution: defnumIslands(self, grid: List[List[str]]) -> int: deffind(index): if parent[index] != index: parent[index] = find(parent[index]) return parent[index] defunion(index1,index2): root1 = find(index1) root2 = find(index2) if root1 != root2: if rank[root1] > rank[root2]: parent[root2] = root1 elif rank[root1] < rank[root2]: parent[root1] = root2 else: parent[root2] = root1 rank[root1] += 1 m = len(grid) n = len(grid[0]) lands = m * n parent = list(range(lands)) rank = [0] * lands
for i inrange(m): for j inrange(n): if grid[i][j] == "1": for x,y in [(i-1,j),(i+1,j),(i,j-1),(i,j+1)]: if0<=x<m and0<=y<n and grid[x][y] == "1": union(i*n+j,x*n+y) islands = sum((parent[i] == i and grid[i//n][i%n] =="1") for i inrange(lands)) return islands
classSolution: defdfs(self, grid, r, c): grid[r][c] = 0 nr, nc = len(grid), len(grid[0]) for x, y in [(r - 1, c), (r + 1, c), (r, c - 1), (r, c + 1)]: if0 <= x < nr and0 <= y < nc and grid[x][y] == "1": self.dfs(grid, x, y)
defnumIslands(self, grid: List[List[str]]) -> int: nr = len(grid) if nr == 0: return0 nc = len(grid[0])
num_islands = 0 for r inrange(nr): for c inrange(nc): if grid[r][c] == "1": num_islands += 1 stack = [(r, c)] while stack: cr, cc = stack.pop() grid[cr][cc] = "0" for x, y in [(cr - 1, cc), (cr + 1, cc), (cr, cc - 1), (cr, cc + 1)]: if0 <= x < nr and0 <= y < nc and grid[x][y] == "1": stack.append((x, y)) return num_islands
n = len(edges) parent = list(range(n)) for fr,to in edges: if union(fr,to): return [fr,to]
题目中所说的edges 中最后出现的那个,其实就是这两个点的连线
滑动窗口
209. 长度最小的子数组
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
classSolution: defminSubArrayLen(self, target: int, nums: List[int]) -> int: start = end = 0 n = len(nums) minLen = n+1 sum = 0 while end<n: sum += nums[end] whilesum>= target: minLen = min(minLen,end - start +1) sum -= nums[start] start += 1 end += 1 return0if minLen == n+1else minLen
for循环的时间复杂度要小于while循环
1 2 3 4 5 6 7 8 9 10 11 12 13
classSolution: defminSubArrayLen(self, target: int, nums: List[int]) -> int: start = end = 0 minLen = len(nums)+1 sum = 0 for end inrange(len(nums)): sum += nums[end] whilesum>= target: minLen = min(minLen,end - start +1) sum -= nums[start] start += 1 return0if minLen == len(nums)+1else minLen
3. 无重复字符的最长子串
本题使用了哈希表作为窗口,用于快速查找是否存在重复元素
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
classSolution: deflengthOfLongestSubstring(self, s: str) -> int: ifnot s:return0 left = 0 lookup = set() max_len = 0 cur_len = 0 for i inrange(len(s)): cur_len += 1 # 当出现重复字符,清空窗口 while s[i] in lookup: lookup.remove(s[left]) left += 1 cur_len -= 1 if cur_len > max_len:max_len = cur_len lookup.add(s[i]) return max_len
前缀和
724. 寻找数组的中心下标
1 2 3 4 5 6 7 8 9
classSolution: defpivotIndex(self, nums: List[int]) -> int: total = sum(nums) sum_right = total for i inrange(len(nums)): sum_right -= nums[i] sum_left = total - sum_right - nums[i] if sum_left == sum_right: return i return -1
560. 和为 K 的子数组
初始化:
dic = {0: 1}:这是一个非常关键的初始化。这表示前缀和为 0 的情况有一个,这对于处理从数组开始到当前元素的和刚好为 k 的情况是必需的。
sums = 0:用来计算当前的前缀和。
res = 0:用来存储结果,即和为 k 的子数组的数量。
遍历数组:
对于每个元素 num,首先更新当前的前缀和 sums += num。
接着检查 sums - k 是否已经在 dic 中出现过,因为如果出现过,说明存在一个 j,使得 pre[i] - pre[j] = k,这正是我们要找的和为 k 的子数组的结束点 i。dic.get(sums-k, 0) 会得到这种情况的次数,加到 res 上。
while queue: start = queue.popleft() if start in visited: continue for end inrange(start + 1, len(s) + 1): if s[start:end] in word_set: if end == len(s): returnTrue queue.append(end) visited.add(start)
classSolution: defshortestBridge(self, grid: List[List[int]]) -> int: defdfs(x,y): stack = [(x,y)] while stack: x, y = stack.pop() if grid[x][y] == -1: continue grid[x][y] = -1 q.append((x, y)) for nx, ny in (x + 1, y), (x - 1, y), (x, y + 1), (x, y - 1): if0 <= nx < n and0 <= ny < n and grid[nx][ny] == 1: stack.append((nx, ny))
n = len(grid) q = deque() i, j = next((i, j) for i inrange(n) for j inrange(n) if grid[i][j]==1) dfs(i,j) ans = 0 while q: for _ inrange(len(q)): i, j = q.popleft() for nx, ny in (i + 1, j), (i - 1, j), (i, j + 1), (i, j - 1): if0 <= nx < n and0 <= ny < n: if grid[nx][ny] == 1: return ans if grid[nx][ny] == 0: grid[nx][ny] = -1 q.append((nx, ny)) ans +=1
动态规划
213. 打家劫舍Ⅱ
转移方程:$ dp[n+1]=max(dp[n],dp[n−1]+num)$
由于是环形,我们可以考虑两种情况:排除第一家、排除最后一家
1 2 3 4 5 6 7 8
classSolution: defrob(self, nums: [int]) -> int: defmy_rob(nums): cur, pre = 0, 0 for num in nums: cur, pre = max(pre + num, cur), cur return cur returnmax(my_rob(nums[:-1]),my_rob(nums[1:])) iflen(nums) != 1else nums[0]
贪心算法
55. 跳跃游戏
1 2 3 4 5 6 7 8 9
classSolution: defcanJump(self, nums: List[int]) -> bool: max_distance = 0 for i inrange(len(nums)): if i <= max_distance: max_distance = max(max_distance,i+nums[i]) if max_distance >= len(nums)-1 : returnTrue returnFalse
435. 无重叠区间
这题的叙述可以转化为最多参加多少个活动
1 2 3 4 5 6 7 8 9 10 11 12
classSolution: deferaseOverlapIntervals(self, intervals: List[List[int]]) -> int: intervals.sort(key=lambda x: x[1]) n = len(intervals) right = intervals[0][1] ans = 1
for i inrange(len(intervals)): if intervals[i][0] >= right: ans += 1 right = intervals[i][1] return n-ans