哈希
1.两数之和
在数组中找两数之和为目标值的数组下标。
- 暴力—— O ( n 2 ) O(n^2) O(n2),没有用到已知信息target
- 使用哈希表,利用target——
O
(
n
)
O(n)
O(n)
(1) 求当前数与target的差值,判断差值是否在dict中
(2)是,则构成两数之和,返回
class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
d = dict()
for i, num in enumerate(nums):
j = target - num
if j in d: # 判断差值是否在字典中
return i,d[j]
d[num] = i # 如果不在则存储,避免重复值的影响
49.字母异位词分组
将str排序,保证不同词的异位词,对应的是同一个key
class Solution:
def groupAnagrams(self, strs: List[str]) -> List[List[str]]:
ans = []
idx = 0
d = dict() # key:sort后的异位词, value:存储在第几个list
for str in strs:
s = ''.join(sorted(str)) # 把每个字符串按序排
if s in d:
ans[d[s]].append(str)
else:
d[s] = idx
tmp = [str]
ans.append(tmp)
idx += 1
return ans
128.最长连续序列(X)
方法1:
(1)set去重
(2)找每个连续序列的开头,即判断是否存在前一个元素
class Solution:
def longestConsecutive(self, nums: List[int]) -> int:
s = set(nums) # 去重
ans = 0
# 判断s中的每个数是否是连续序列的开头
# 即,是否存在前一个数
for i in s:
if (i-1) not in s:
tmp = 1
cur = i
while (cur + 1) in s:
tmp += 1
cur += 1
ans = max(ans, tmp)
return ans
方法2:
(1)每次新进来哈希表一个数,判断当前数加入后,构成的连续序列的长度
class Solution:
def longestConsecutive(self, nums: List[int]) -> int:
res = 0
hash_dict = dict()
for num in nums:
# 新进来哈希表一个数
if num not in hash_dict:
# 获取当前数的最左边连续长度,没有的话就更新为0
left = hash_dict.get(num-1,0)
# 同理获取右边的数
right = hash_dict.get(num+1,0)
# 把当前数加入哈希表,代表当前数字出现过
hash_dict[num] = 1
# 更新长度
length = left+1+right # 左边长度+右边长度+当前位置1
res = max(res,length)
# 更新最左端点的值,如果left=n存在,那么证明当前数的前n个都存在哈希表中
hash_dict[num-left] = length
# 更新最右端点的值,如果right=n存在,那么证明当前数的后n个都存在哈希表中
hash_dict[num+right] = length
# 此时 【num-left,num-right】范围的值都连续存在哈希表中了
# 即使left或者right=0都不影响结果
return res
滑动窗口
3. 无重复字符的最长子串(X)
双指针滑动窗口,维护窗口[l, r],保证窗口内没有重复的元素
(1)控制右指针往右走,并通过哈希表快速查询是否出现重复元素
(2)如果出现重复元素,则控制左指针玩右走,从窗口中删除两个重复元素范围外的元素,同时删除左边的重复元素,保证新窗口无重复元素。
from collections import defaultdict
class Solution:
def lengthOfLongestSubstring(self, s: str) -> int:
d = defaultdict(int)
l,ans = 0,0
for r in range(len(s)):
d[ s[r] ] += 1
if d[s[r]] > 1: # 右指针的字符与窗口内字符出现重复
while d[s[l]] == 1: # 找到重复的字符
d[s[l]] = 0
l += 1
d[s[l]] -= 1 # 修改重复字符为不重复, 重新寻找下一个串
l += 1
ans = max(ans, r-l+1)
return ans
438.找到字符串中所有字母异位词(X)
维护一个大小与p相等的窗口,判断窗口的字符数是否与目标一致
(1)官方题解:
class Solution:
def findAnagrams(self, s: str, p: str) -> List[int]:
len_s, len_p = len(s), len(p)
ans = []
letter_s, letter_p = [0]*26, [0]*26
if len_s < len_p: # 不存在异位词
return ans
for i in range(len_p):
letter_s[ord(s[i]) - 97] += 1
letter_p[ord(p[i]) - 97] += 1
if letter_s == letter_p: # 判断前面len_p个是否相等
ans.append(0)
for i in range(len_s - len_p): # 剩余长度小于len_p时,不需要继续
# 把第i个元素移除窗口
# 把 i + len_p 的元素加入窗口
letter_s[ord(s[i])-97] -= 1
letter_s[ord(s[i + len_p])-97] += 1
if letter_s == letter_p:
ans.append(i+1)
return ans
(2)暴力(擦边过)
class Solution:
def findAnagrams(self, s: str, p: str) -> List[int]:
len_s, len_p = len(s), len(p)
p = "".join(sorted(p))
ans = []
if len_s < len_p:
return ans
for i in range(len_s - len_p + 1):
if "".join(sorted(s[i:i+len_p])) == p:
ans.append(i)
return ans