classSolution: deftwoSum(self, nums: List[int], target: int) -> List[int]: n = len(nums) for i inrange(n): for j inrange(i + 1, n): if nums[i] + nums[j] == target: return [i, j] return []
时间复杂度:$O(n^2)$ 空间复杂度:$O(1)$
1 2 3 4 5 6 7 8
classSolution: deftwoSum(self, nums: List[int], target: int) -> List[int]: hashtable = dict() for i, num inenumerate(nums): if target - num in hashtable: return [hashtable[target - num], i] hashtable[nums[i]] = i return []
classSolution: deflongestConsecutive(self, nums: List[int]) -> int: st=set(nums) ans=0 for x in st: if x-1in st: continue y=x+1 while y in st: y+=1 ans = max(ans,y-x) return ans
时间复杂度是 O(n),其中 n 是数组 nums 的长度。
创建集合 set(nums):这一步将所有元素放入集合中,时间复杂度为 O(n)。
主循环 for x in st:这个循环会遍历集合中的每个元素。乍一看似乎会有 O(n) 次迭代,但关键在于循环内部的优化。
关键优化 if x-1 in st: continue:这个条件检查非常重要。它确保只有当 x 是某个连续序列的起点时(即 x-1 不在集合中),才会继续执行后续操作。这意味着对于任何连续序列,我们只会在该序列的最小元素处执行完整的 while 循环。
while 循环:对于每个连续序列的起点,while 循环会计算该序列的长度。每个元素在所有 while 循环中最多被访问一次。
classSolution: defmoveZeroes(self, nums: List[int]) -> None: """ Do not return anything, modify nums in-place instead. """ j=0 for i inrange(len(nums)): if nums[i]!=0: nums[i],nums[j]=nums[j],nums[i] j+=1
1 2 3 4 5 6 7 8 9 10 11 12
classSolution: defmoveZeroes(self, nums: List[int]) -> None: """ Do not return anything, modify nums in-place instead. """ m=0 for x in nums:# 扫描速度不慢于赋值速度 if x!=0: nums[m]=x m+=1 for n inrange(m,len(nums)): nums[n]=0
盛最多水的容器
给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。 找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。 返回容器可以储存的最大水量。 说明:你不能倾斜容器。
1 2 3 4 5 6 7 8
classSolution: defmaxArea(self, height: List[int]) -> int: # 时间复杂度O(n^2) ans=0 for i inrange(len(height)-1): for j inrange (i+1,len(height)): ans= max(ans,min(height[i],height[j])*(j-i)) return ans
1 2 3 4 5 6 7 8 9 10 11 12 13
classSolution: defmaxArea(self, height: List[int]) -> int: left,right=0,len(height)-1 ans=0 while left<right: area= min(height[left],height[right])*(right-left) ans=max(area,ans) if height[left]<height[right]: left+=1 else: right -=1 return ans
classSolution: defthreeSum(self, nums: list[int]) -> list[list[int]]: nums.sort() ans=[] for i inrange(0,len(nums)-2): if nums[i]>0: break if i >0and nums[i]==nums[i-1]: continue l=i+1 r=len(nums)-1 while l<r: total= nums[i]+nums[l]+nums[r] if total==0: ans.append([nums[i],nums[l],nums[r]]) while l < r and nums[l] == nums[l + 1]: l += 1 while l < r and nums[r] == nums[r - 1]: r -=1 l+=1 r-=1 elif total<0: l+=1 else: r-=1
classSolution: deftrap(self, height: List[int]) -> int: leftmax=[0]*len(height) leftmax[0]=height[0] rightmax=[0]*len(height) rightmax[len(height)-1]=height[-1] ans=0 for i inrange(1,len(height)): leftmax[i]=max(height[i],leftmax[i-1]) for j inrange(len(height)-2,-1,-1): rightmax[j]=max(height[j],rightmax[j+1]) for m inrange(len(height)): ans=ans+min(leftmax[m],rightmax[m])-height[m] return ans
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
classSolution: deftrap(self, height: List[int]) -> int: l=0 r=len(height)-1 ans=0 leftmax=height[l] rightmax=height[r] while l<=r: if leftmax<rightmax: ans=ans+leftmax-height[l] l+=1 leftmax=max(leftmax,height[l]) else: ans=ans+rightmax-height[r] r-=1 rightmax=max(rightmax,height[r]) return ans
1 2 3 4 5 6 7 8 9 10 11 12 13 14
classSolution: deftrap(self, height: List[int]) -> int: ans=0 st=[] for i,h inenumerate(height): while st and h>height[st[-1]]: bottom_h=height[st.pop()] iflen(st)==0: break dh=min(h,height[st[-1]])-bottom_h ans+=dh*(i-st[-1]-1) st.append(i) return ans
classSolution: deflengthOfLongestSubstring(self, s: str) -> int: ans=0 right=0 map=set() for left inrange(len(s)): if left>0: map.remove(s[left-1]) while right< len(s) and s[right] notinmap: map.add(s[right]) right+=1 ans=max(ans,right-left) return ans
classSolution: deflengthOfLongestSubstring(self, s: str) -> int: ans=0 left=0 map=set() for right,x inenumerate(s): while x inmap: map.remove(s[left]) left+=1 map.add(x) ans=max(ans,right-left+1) return ans
遍历右指针,固定,调整左指针
1 2 3 4 5 6 7 8 9 10 11 12 13
classSolution: deflengthOfLongestSubstring(self, s: str) -> int: ans=0 left=0 map=defaultdict(int) for right,x inenumerate(s): map[x]+=1 whilemap[x]>1: map[s[left]]-=1 left+=1 ans=max(ans,right-left+1) return ans
找到字符串中所有字母异位词
给定两个字符串 s 和 p,找到 s 中所有 p 的 异位词 的子串,返回这些子串的起始索引。不考虑答案输出的顺序。 示例 1: 输入: s = “cbaebabacd”, p = “abc” 输出: [0,6] 解释: 起始索引等于 0 的子串是 “cba”, 它是 “abc” 的异位词。 起始索引等于 6 的子串是 “bac”, 它是 “abc” 的异位词。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
classSolution: deffindAnagrams(self, s: str, p: str) -> List[int]: cnt_p=Counter(p) cnt_s=Counter() left=0 ans=[] for right,x inenumerate(s): cnt_s[x]+=1 if right < len(p)-1: continue if cnt_p==cnt_s: ans.append(left) cnt_s[s[left]]-=1 left+=1 return ans
1 2 3 4 5 6 7 8 9 10 11 12 13
classSolution: deffindAnagrams(self, s: str, p: str) -> List[int]: cnt=Counter(p) ans=[] left=0 for right,x inenumerate(s): cnt[x]-=1 while cnt[x]<0: cnt[s[left]]+=1 left+=1 if right-left+1==len(p): ans.append(left) return ans
和为 K 的子数组
给你一个整数数组 nums 和一个整数 k ,请你统计并返回 该数组中和为 k 的子数组的个数 。 子数组是数组中元素的连续非空序列。 示例 1: 输入:nums = [1,1,1], k = 2 输出:2
1 2 3 4 5 6 7 8 9 10 11 12
classSolution: defsubarraySum(self, nums: List[int], k: int) -> int: # 计算前缀和,第一个为0,保证如果前缀和-k=0时计数 sum=[0]*(len(nums)+1) ans=0 for i ,x inenumerate(nums): sum[i+1] =sum[i]+x cnt=defaultdict(int) for x insum: ans+=cnt[x-k] cnt[x]+=1 return ans
滑动窗口最大值
给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。 返回 滑动窗口中的最大值 。 示例 1: 输入:nums = [1,3,-1,-3,5,3,6,7], k = 3 输出:[3,3,5,5,6,7]
用双端队列做单调栈,保存窗口滑动时的索引
1 2 3 4 5 6 7 8 9 10 11 12 13 14
classSolution: defmaxSlidingWindow(self, nums: List[int], k: int) -> List[int]: ans=[] q=deque() for i,x inenumerate(nums): # 保证索引对应值的单调性 while q and nums[q[-1]]<=x: q.pop() q.append(i) if q[0]<i-k+1: q.popleft() if i>=k-1: ans.append(nums[q[0]]) return ans
最小覆盖子串
给定两个字符串 s 和 t,长度分别是 m 和 n,返回 s 中的 最短窗口 子串,使得该子串包含 t 中的每一个字符(包括重复字符)。如果没有这样的子串,返回空字符串 “”。 测试用例保证答案唯一。 输入:s = “ADOBECODEBANC”, t = “ABC” 输出:”BANC” 解释:最小覆盖子串 “BANC” 包含来自字符串 t 的 ‘A’、’B’ 和 ‘C’
用双指针扫描,遍历右指针,左指针右移
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
classSolution: defminWindow(self, s: str, t: str) -> str: cnt_s=Counter() cnt_t=Counter(t) ans_left=-1 ans_right=len(s)-1 left=0 for right ,x inenumerate(s): cnt_s[x]+=1 while cnt_s>=cnt_t: if right-left<ans_right-ans_left: ans_left,ans_right=left,right cnt_s[s[left]]-=1 left+=1 return""if ans_left<0else s[ans_left:ans_right+1]
classSolution: defmerge(self, intervals: List[List[int]]) -> List[List[int]]: intervals.sort(key=lambda p: p[0]) ans=[] for x in intervals: if ans and ans[-1][1]>=x[0]: ans[-1][1]=max(ans[-1][1],x[1]) else: ans.append(x) return ans
轮转数组
给定一个整数数组 nums,将数组中的元素向右轮转 k 个位置,其中 k 是非负数。 示例 1: 输入: nums = [1,2,3,4,5,6,7], k = 3 输出: [5,6,7,1,2,3,4] 解释: 向右轮转 1 步: [7,1,2,3,4,5,6] 向右轮转 2 步: [6,7,1,2,3,4,5] 向右轮转 3 步: [5,6,7,1,2,3,4]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
classSolution: defrotate(self, nums: List[int], k: int) -> None: """ Do not return anything, modify nums in-place instead. """ defreverse(i:int,j:int)->None: while i<j: nums[i],nums[j]=nums[j],nums[i] i+=1 j-=1 n=len(nums) k%=n reverse(0,n-1) reverse(0,k-1) reverse(k,n-1)
1 2 3 4 5 6 7 8
classSolution: defrotate(self, nums: List[int], k: int) -> None: """ Do not return anything, modify nums in-place instead. """ n = len(nums) k %= n nums[:] = nums[n-k:] + nums[:n-k]
classSolution: deffirstMissingPositive(self, nums: List[int]) -> int: n=len(nums) for i inrange(n): while1<=nums[i]<=n and nums[nums[i]-1]!=nums[i]: j=nums[i]-1#应该坐的位置 nums[i],nums[j]=nums[j],nums[i] for i inrange(n): if nums[i]!=i+1: return i+1 return n+1
矩阵置零
给定一个 m x n 的矩阵,如果一个元素为 0 ,则将其所在行和列的所有元素都设为 0 。请使用 原地 算法。
classSolution: defsetZeroes(self, matrix: List[List[int]]) -> None: """ Do not return anything, modify matrix in-place instead. """ m=len(matrix) n=len(matrix[0]) x=0in matrix[0] y=any(row[0]==0for row in matrix) for i inrange(1,m): for j inrange(1,n): if matrix[i][j]==0: matrix[i][0]=0 matrix[0][j]=0 for i inrange(1,m): for j inrange(1,n): if matrix[i][0]==0or matrix[0][j]==0: matrix[i][j]=0 if x: for j inrange(n): matrix[0][j]=0 if y: for row in matrix: row[0]=0
螺旋矩阵
给你一个 m 行 n 列的矩阵 matrix ,请按照 顺时针螺旋顺序 ,返回矩阵中的所有元素。
遇到边界,右转,遵循右(行不变,列加1,右转到)下(行加1,列不变,右转到)左(右转到)上
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
classSolution: defspiralOrder(self, matrix: List[List[int]]) -> List[int]: direction=(0,1),(1,0),(0,-1),(-1,0)#右,下,左,上 ans=[] i=j=di=0 row=len(matrix) col=len(matrix[0]) for _ inrange(row*col): ans.append(matrix[i][j]) matrix[i][j]=None x=i+direction[di][0] y=j+direction[di][1] if x<0or x>=row or y<0or y>=col or matrix[x][y]==None: di=(di+1)%4 i+=direction[di][0] j+=direction[di][1] return ans
旋转图像
给定一个 n × n 的二维矩阵 matrix 表示一个图像。请你将图像顺时针旋转 90 度。 你必须在 原地 旋转图像,这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图像。
先沿主对角线反转,再每行翻转
1 2 3 4 5 6 7 8 9 10 11
classSolution: defrotate(self, matrix: List[List[int]]) -> None: """ Do not return anything, modify matrix in-place instead. """ n=len(matrix) for i inrange(n): for j inrange(i+1,n): matrix[i][j],matrix[j][i]=matrix[j][i],matrix[i][j] for row in matrix: row.reverse()
搜索二维矩阵 II
编写一个高效的算法来搜索 m x n 矩阵 matrix 中的一个目标值 target 。该矩阵具有以下特性: 每行的元素从左到右升序排列。 每列的元素从上到下升序排列。
找上升和下降的边界,比一次,知道一行或一列的信息,进行调整
1 2 3 4 5 6 7 8 9 10 11 12 13
classSolution: defsearchMatrix(self, matrix: List[List[int]], target: int) -> bool: m=len(matrix) n=len(matrix[0]) i,j=0,n-1 while i<m and j>=0: if matrix[i][j]==target: returnTrue elif matrix[i][j]<target: i+=1 else: j-=1 returnFalse