1.两数之和

解法:
class Solution(object):
def twoSum(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: List[int]
"""
num_map={}
for i,num in enumerate(nums):
a=target-num
if a in num_map:
return (num_map[a],i)
num_map[num]=i
1.定义一个字典,用来接收已经遍历的值和对应的下标
2.用target减去当前遍历的值,判断结果是否在字典里,若存在,返回二者下标,如不存在,将该值以及下标存进字典里
enumerate 是 Python 内置函数,用于同时获取可迭代对象(如列表、元组、字符串等)的元素及其对应的索引(下标)。
2.字母异位词分组

解法:
class Solution(object):
def groupAnagrams(self, strs):
"""
:type strs: List[str]
:rtype: List[List[str]]
"""
anagram_map={}
for str in strs:
sorted_s="".join(sorted(str))
if sorted_s in anagram_map:
anagram_map[sorted_s].append(str)
else:
anagram_map[sorted_s]=[str]
return list(anagram_map.values())
思路:
1.因为异位词的每个字母和数量是相同的,那么将每个词的字母进行排序,那么这个所有的异位词就一样了
2.使用字典,将异位词排序后的字符串作为key,然后将排序后的词添加到对应的列表中
3.最后将字典的值导出,转化为列表,返回结果
语法:
sorted(s): Python 内置函数,对字符串s中的字符进行排序,返回一个排序后的字符列表。例如:s = "eat"时,sorted(s)会返回['a', 'e', 't'](按字母顺序排序)。''.join(...): 字符串的 join 方法,将一个可迭代对象(这里是排序后的字符列表)拼接成一个字符串。
例如:''.join(['a', 'e', 't']) 会返回 "aet",作为字典的键。
anagram_map.values(): 字典的values方法,返回一个包含所有值的视图(这里每个值都是一个字母异位词分组的列表)。
3.最长连续序列

class Solution(object):
def longestConsecutive(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
nums_set=set(nums)
longest=0
for num in nums_set:
cur_len=1
cur_num=num
if num-1 not in nums_set:
while cur_num+1 in nums_set:
cur_len+=1
cur_num+=1
longest=max(longest,cur_len)
return longest
思路:
1.利用set集合去掉重复的数
2.利用set集合查找元素的时间复杂度较低
3.查找每段连续的数的开始位置,如果num-1存在于set集合中,那么他就不是这一段数中最开始的数
4.找到最开始的数后,循环判断后面的是否在集合里面,如果在就更新长度,如果不在,就用统计的长度和最长值进行比较
5.返回最大值
4.移动零

class Solution(object):
def moveZeroes(self, nums):
"""
:type nums: List[int]
:rtype: None Do not return anything, modify nums in-place instead.
"""
left=right=0
n=len(nums)
while right<n:
if nums[right]!=0:
nums[left],nums[right]=nums[right],nums[left]
left+=1
right+=1
思路:
1.使用双指针
2.使用right向后遍历,遇到不是0的数就和left位置交换
3.每次交换完,left++
4.每次遍历一个数,right++
5.相当于以left为界,left左边的数是非0数,left右边的数是0,right向后遍历未处理的数,遇到非0数,就将其放到left左边
5.盛最多水的容器


class Solution(object):
def maxArea(self, height):
"""
:type height: List[int]
:rtype: int
"""
l,r=0,len(height)-1
maxArea=0
while l<r:
area=min(height[l],height[r])*(r-l)
maxArea=max(area,maxArea)
if height[l]<=height[r]:
l+=1
else:
r-=1
return maxArea
思路:
1.从容器的两边向内寻找最大容器,此时容器的底是最大的
2.每次改变一边,哪一边短就向内靠拢,寻找最大容器
3.left++,right--,为了寻找最大的容器,如果不是短板移动,那么底不断变小,但高始终取决于短板,那么他的容器大小始终不会变高
6.三数之和

class Solution(object):
def threeSum(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
n=len(nums)
nums.sort()
res=[]
for i in range(n):
if nums[i]>0:
break
if nums[i]==nums[i-1] and i>0:
continue
l,r=i+1,n-1
while l<r:
total=nums[l]+nums[r]
if -nums[i]>total:
l+=1
elif -nums[i]<total:
r-=1
else:
res.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
return res
思路:
1.对列表排序,方便去重
2.遍历列表,出现重复的数跳过
3.获取到遍历的元素的相反数,在其右边区间使用双指针,求和和相反数进行比较,大于相反数,right--,小于相反数,left++
4.等于相反数,循环查找下一对等于相反数的组合,遇到相同的数,跳过
5.返回列表
7.接雨水

class Solution(object):
def trap(self, height):
"""
:type height: List[int]
:rtype: int
"""
if not height:
return 0
n=len(height)-1
res=0
left_max=height[0]
right_max=height[n]
l,r=0,n
while l<r:
if height[l]<height[r]:
if height[l]<left_max:
res+=left_max-height[l]
else:
left_max=height[l]
l+=1
else:
if height[r]<right_max:
res+=right_max-height[r]
else:
right_max=height[r]
r-=1
return res
1. 核心逻辑:单个柱子的接水量
对于任意一个柱子,它能接住的雨水量 =
min(左侧最高柱高度, 右侧最高柱高度) - 自身高度(若结果为正,则该值为接水量;若为负,接水量为 0)。比如示例中某个高度为
0的柱子,其左侧最高柱是2,右侧最高柱是3,那么它能接的水量就是min(2, 3) - 0 = 2。2. 双指针法的合理性
我们用两个指针
left(从左往右)和right(从右往左)遍历数组,同时维护left_max(left左侧的最高柱高度)和right_max(right右侧的最高柱高度)。
当
height[left] < height[right]时:因为right右侧存在比height[left]更高的柱(否则height[right]不会更大),所以left位置的 ** 左侧最高柱left_max** 就是它的 "左边界",此时可直接用left_max - height[left]计算接水量(或更新left_max)。当
height[left] >= height[right]时:同理,right位置的 ** 右侧最高柱right_max** 就是它的 "右边界",此时可直接用right_max - height[right]计算接水量(或更新right_max)。这种方式确保了每个柱子仅被遍历一次,同时准确利用了 "左右最高柱的较矮者" 这一核心逻辑,从而高效解决问题。
8.无重复字符的最长子串

class Solution(object):
def lengthOfLongestSubstring(self, s):
"""
:type s: str
:rtype: int
"""
char_map={}
left=0
max_len=0
for right in range(len(s)):
if s[right] in char_map and char_map[s[right]]>=left:
left=char_map[s[right]]+1
char_map[s[right]]=right
max_len=max(max_len,right-left+1)
return max_len
思路:
1.利用滑动窗口
利用right指针向右遍历,将遍历的字符和下标存入字典中
2.当right向右遍历的过程中,判断当前字符是否存在于字典中,并且上一次索引在left之后,那么这个字符就在窗口中,就将left指向上一次出现索引的后一位,并计算当前无重复字符串的最大长度
9.找到字符串中所有字母异位词

class Solution(object):
def findAnagrams(self, s, p):
"""
:type s: str
:type p: str
:rtype: List[int]
"""
s_len=len(s)
p_len=len(p)
if p_len>s_len:
return []
s_count=[0]*26
p_count=[0]*26
ans=[]
for i in range(p_len):
s_count[ord(s[i])-97]+=1
p_count[ord(p[i])-97]+=1
if s_count==p_count:
ans.append(0)
for i in range(s_len-p_len):
s_count[ord(s[i])-97]-=1
s_count[ord(s[i+p_len])-97]+=1
if s_count==p_count:
ans.append(i+1)
return ans
思路:
1.使用滑动窗口
2。利用数组统计每个字符出现的次数,也统计s字符串相同长度下,每个字符出现的次数
每次将窗口向后移动一格,判断两个维护的数组是否相等,若相等,则找到一个异位词
class Solution(object):
def findAnagrams(self, s, p):
"""
:type s: str
:type p: str
:rtype: List[int]
"""
s_len,p_len=len(s),len(p)
if p_len>s_len:
return []
count=[0]*26
ans=[]
len1=s_len-p_len
for i in range(p_len):
count[ord(s[i])-97]+=1
count[ord(p[i])-97]-=1
differ=[c!=0 for c in count].count(True)
if differ==0:
ans.append(0)
for j in range(s_len-p_len):
if count[ord(s[j])-97]==1:
differ-=1
elif count[ord(s[j])-97]==0:
differ+=1
count[ord(s[j])-97]-=1
if count[ord(s[j+p_len])-97]==-1:
differ-=1
elif count[ord(s[j+p_len])-97]==0:
differ+=1
count[ord(s[j+p_len])-97]+=1
if differ==0:
ans.append(j+1)
return ans
10.和为k的子数组

class Solution(object):
def subarraySum(self, nums, k):
"""
:type nums: List[int]
:type k: int
:rtype: int
"""
count=0
sum_map=defaultdict(int)
pre_sum=0
sum_map[0]=1
for num in nums:
pre_sum+=num
if pre_sum-k in sum_map:
count+=sum_map[pre_sum-k]
sum_map[pre_sum]+=1
return count
思路:
利用前缀和和hash表
1.因为子数组是连续的,我们使用前缀和,就可以获取到中间某段数组的和
2.中间某段数组的和我们希望是目标值k,而目标值k是确定的,所以我们需要看后一段前缀和减去k的值,在前面的前缀和中出现了几次,则找到几个前缀和数组
3.前缀和出现的次数我们使用hash表来存储
语法:
在遍历数组时,我们需要频繁查询哈希表中是否存在某个前缀和(即 preSum - k)。如果使用普通字典(如 dict),当查询的键不存在时会抛出 KeyError,需要手动判断或捕获异常。
而defaultdict可以指定一个默认值类型(这里用 int),当查询的键不存在时,会自动返回该类型的默认值(int 的默认值是 0)。
细节:
初始化时,将sum_map[0]=1,当我们刚开始遍历第一个元素时,map里面为空,而如果第一个元素就为目标值时,前缀和里面找不到和为0的数组,但其实,他一个元素就能构成目标子数组,初始化的目的是为了防止一个元素构成目标子数组的情况