日常系列LeetCode《9·哈希查找篇》
Posted 常某某的好奇心
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了日常系列LeetCode《9·哈希查找篇》相关的知识,希望对你有一定的参考价值。
数据规模->时间复杂度
<=10^4 😮(n^2)
<=10^7:o(nlogn)
<=10^8:o(n)
10^8<=:o(logn),o(1)
总结
通过索引随机访问数组元素时间复杂度:'O(1)
lc 771:宝石与石头
https://leetcode.cn/problems/jewels-and-stones/
提示:
1 <= jewels.length, stones.length <= 50
jewels 和 stones 仅由英文字母组成
jewels 中的所有字符都是 唯一的
#方案一:哈希set
class Solution:
def numJewelsInStones(self, jewels: str, stones: str) -> int:
#o(m)
hashset=set(jewels)
#O(1*n)
return sum(s in hashset for s in stones)
#方案二(优化):数组代替哈希
class Solution:
def numJewelsInStones(self, jewels: str, stones: str) -> int:
#o(52+6)
#key:j中的字母不重复,和S中的所有字符都是字母
count=[0]*(ord('z')-ord('A')+1)
for c in jewels:
count[ord(c)-ord('A')] =1
#O(1*n)
res=0
for c in stones:
if count[ord(c)-ord('A')]==1:
res+=1
#
return res
#
lc 888 :公平的糖果棒交换
https://leetcode.cn/problems/fair-candy-swap/
提示:
1 <= aliceSizes.length, bobSizes.length <= 10^4
1 <= aliceSizes[i], bobSizes[j] <= 10^5
爱丽丝和鲍勃的糖果总数量不同。
题目数据保证对于给定的输入至少存在一个有效答案。
class Solution:
def fairCandySwap(self, aliceSizes: List[int], bobSizes: List[int]) -> List[int]:
#
suma=sum(aliceSizes)
sumb=sum(bobSizes)
delta=suma-sumb
#o(1*n)
hashset=set(aliceSizes)
for y in bobSizes:
x=y+delta//2
if x in hashset:
return [x,y]
lc 128【剑指 119】【top100】 :最长连续序列
https://leetcode.cn/problems/longest-consecutive-sequence/
请你设计并实现时间复杂度为 O(n) 的算法解决此问题。
提示:
0 <= nums.length <= 10^5
-10^9 <= nums[i] <= 10^9
#排序解法:(不满足)
class Solution:
def longestConsecutive(self, nums: List[int]) -> int:
#o(nlogn),#o(n)
s=sorted(nums)
if len(s)<2:return len(s)
#
res=1
count=1
for i in range(1,len(s)):
if s[i]==s[i-1]:continue
if s[i]-s[i-1]==1:count+=1
else:
res=max(res,count)#本次统计更新
count=1#下次统计初始
#
return max(res,count) #key:防止一直累加
#哈希
class Solution:
def longestConsecutive(self, nums: List[int]) -> int:
#o(n)
if len(nums) < 2: return len(nums)
hashset=set(nums)
#o(1*n)
cnt=1
res=1
for num in nums:
if num-1 in hashset:continue #key:从最小开始
cur_num=num
while cur_num+1 in hashset: #key:while
cur_num=cur_num+1
cnt+=1
else:
res=max(cnt,res)
cnt=1
return max(res,cnt) #key:防止一直累加
lc 136 【top100】:只出现一次的数字
https://leetcode.cn/problems/single-number/
说明:
你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?
思路:暴力->排序->hashmap
#方案一:hashmap(不满足)
class Solution:
def singleNumber(self, nums: List[int]) -> int:
#o(n)
hashmap=
for num in nums:
cnt=1
if num in hashmap:cnt=hashmap[num]+1
hashmap[num]=cnt #key:map对应
#o(n)
for k,v in hashmap.items():
if v==1:return k
#方案二:位运算
class Solution:
def singleNumber(self, nums: List[int]) -> int:
#key:异或
#o(1)
base=0
#o(1)
for num in nums:
base^=num
#
return base
lc 389:找不同
https://leetcode.cn/problems/find-the-difference/
提示:
0 <= s.length <= 1000
t.length == s.length + 1
s 和 t 只包含小写字母
#方案一:数组统计字符出现的次数
class Solution:
def findTheDifference(self, s: str, t: str) -> str:
#o(26),o(n)
cnt=[0]*26
for c in s:cnt[ord(c)-ord('a')]+=1
for c in t:
cnt[ord(c)-ord('a')]-=1
if cnt[ord(c)-ord('a')]<0:return c
#方案二:chr(st-ss)
class Solution:
def findTheDifference(self, s: str, t: str) -> str:
#o(1),o(n)
ss=st=0
for c in s:ss +=ord(c)
for c in t:st +=ord(c)
return chr(st-ss)
#方案三:异或
class Solution:
def findTheDifference(self, s: str, t: str) -> str:
#o(1),o(n)
ss=0
for c in s:ss ^=ord(c)
for c in t:ss ^=ord(c)
return chr(ss)
lc 554:砖墙
https://leetcode.cn/problems/brick-wall/
提示:
n == wall.length
1 <= n <= 10^4
1 <= wall[i].length <= 10^4
1 <= sum(wall[i].length) <= 2 * 10^4
对于每一行 i ,sum(wall[i]) 是相同的
1 <= wall[i][j] <= 2^31 - 1
'''
key:为了尽可能少的穿过砖,垂直线穿过的边缘应该尽量的多
'''
#hashmap
class Solution:
def leastBricks(self, wall: List[List[int]]) -> int:
#o(n)
freq_map=
max_freq=0
#o(m^n)
for i in range(len(wall)):
width=0
for j in range(len(wall[i])-1):
width+=wall[i][j]
if width in freq_map:
freq_map[width]+=1
else:
freq_map[width]=1
max_freq=max(max_freq,freq_map[width])
#
return len(wall)-max_freq
lc 205:同构字符串
https://leetcode.cn/problems/isomorphic-strings/
提示:
1 <= s.length <= 5 * 10^4
t.length == s.length
s 和 t 由任意有效的 ASCII 字符组成
'''
key('双向单一映射'):不同字符不能映射到同一个字符上,相同字符只能映射到同一个字符上,字符可以映射到自己本身。
'''
class Solution:
def isIsomorphic(self, s: str, t: str) -> bool:
st=
ts=
for c1,c2 in zip(s,t):
#'单一映射'
if st.get(c1,c2)!=c2 or ts.get(c2,c1)!=c1:
return False
#
st[c1],ts[c2]=c2,c1
return True
lc 290:单词规律
https://leetcode.cn/problems/word-pattern/
提示:
1 <= pattern.length <= 300
pattern 只包含小写英文字母
1 <= s.length <= 3000
s 只包含小写英文字母和 ’ ’
s 不包含 任何前导或尾随对空格
s 中每个单词都被 单个空格 分隔
class Solution:
def wordPattern(self, pattern: str, s: str) -> bool:
#
s=s.split(' ')
if len(pattern) != len(s):return False
#o(n),o(n)
s1,s2=,
for c1,c2 in zip(pattern,s):
if s1.get(c1,c2)!=c2 or s2.get(c2,c1)!=c1:return False
s1[c1],s2[c2]=c2,c1
return True
lc 242【剑指 032】:有效的字母异位词
https://leetcode.cn/problems/valid-anagram/
提示:
1 <= s.length, t.length <= 5 * 10^4
s 和 t 仅包含小写字母
进阶:
如果输入字符串包含 unicode 字符怎么办?你能否调整你的解法来应对这种情况?
#只包含小写字母
class Solution:
def isAnagram(self, s: str, t: str) -> bool:
if len(s)!=len(t):return False
#o(26),o(n)
cnt=[0]*26
for c in s:cnt[ord(c)-ord('a')]+=1
for c in t:
cnt[ord(c)-ord('a')]-=1
if cnt[ord(c)-ord('a')]<0:return False
return True
#若包含 unicode 字符
class Solution:
def isAnagram(self, s: str, t: str) -> bool:
if len(s)!=len(t):return False
#o(n),o(n)
ss=
for c1 in s:
if c1 in ss:ss[c1]+=1
else:ss[c1]=1
for c2 in t:
if c2 in ss:ss[c2]-=1
if not c2 in ss or ss[c2]<0:return False #key:重复或不存在
#
return True
#排序解法
class Solution:
def isAnagram(self, s: str, t: str) -> bool:
if len(s)!=len(t):return False
#o(nlogn),o(n)
s=sorted(s)
t=sorted(t)
if s==t:return True
else:return False
lc 49【剑指 033】【top100 :字母异位词分组
https://leetcode.cn/problems/group-anagrams/
提示:
1 <= strs.length <= 10^4
0 <= strs[i].length <= 100
strs[i] 仅包含小写字母
'''
value:["eat" , "tea" , ate"] --> key:aet
'''
#方案一:排序+map
import collections
class Solution:
def groupAnagrams(self, strs: List[str]) -> List[List[str]]:
mp=collections.defaultdict(list)
for st in strs:
key=''.join(sorted(st))
mp[key].append(st)#key:append
return list(mp.values())
#仅包含小写字母
import collections
class Solution:
def groupAnagrams(self, strs: List[str]) -> List[List[str]]:
mp=collections.defaultdict(list)
for st in strs:
cnt=[0]*26
for c in st:cnt[ord(c)-ord('a')]+=1
key=tuple(cnt) #tuple
mp[key].append(st)#key:append
return list(mp.values())
lc 560【剑指 010】【top100】:和为K的子数组
https://leetcode.cn/problems/subarray-sum-equals-k/
提示:
1 <= nums.length <= 2 * 10^4
-1000 <= nums[i] <= 1000
-10^7 <= k <= 10^7
#方案一:前缀和+线性查找(超时)
class Solution:
def subarraySum(self, nums: List[int], k: int) -> int:
#o(n)
n=len(nums)
prefixsum=[0]*(n+1)
for i in range(1,n+1):
prefixsum[i]=prefixsum[i-1]+nums[i-1]
#o(n^2)
cnt=0
for j in range(n+1):
diff=prefixsum[j]-k
for i in range(j):
#if prefixsum[j]-prefixsum[i]==k:return True
if prefixsum[i]==diff:cnt+=1
return cnt
#方案二:前缀和+哈希查找(空间换时间)
class Solution:
def subarraySum(self, nums: List[int], k: int) -> int:
n=len(nums)
#o(n)
prefixsum=[0]*(n+1)
for i in range(1,n+1):
prefixsum[i]=prefixsum[i-1]+nums[i-1]
#o(1*n)
mp= #0对应一次
res=0
for j in range(n+1):
#找(0->j-1)
diff=prefixsum[j]-k
if diff in mp:res+=mp[diff]
#建:key-先找后建(相当于从<j前面元素找)
mp[prefixsum[j]]=mp.get(prefixsum[j],0)+1 #默认0+1
return res
#方案三:最优化(单变量代替前缀和数组)
class Solution:
def subarraySum(self, nums: List[int], k: int) -> int:
n=len(nums)
#o(1)
mp=0:1 #prefixsum[0]=0
res=prefixsum=0
#o(1*n)
for num in nums:
prefixsum+=num #prefixsum[1]开始
#找(0->j-1)
diff=prefixsum-k
if diff in mp:res+=mp[diff]
#建:key-先找后建(相当于从<j前面元素找)
mp[prefixsum]=mp.get(prefixsum,0)+1 #默认0+1
return res
lc 41:缺失的第一个正数
https://leetcode.cn/problems/first-missing-positive/
提示:
请你实现时间复杂度为 O(n) 并且只使用常数级别额外空间的解决方案。
1 <= nums.length <= 5 * 10^5
-2^31 <= nums[i] <= 2^31 - 1
#方案一:哈希查找
class Solution:
def firstMissingPositive(self, nums: List[int]) -> int:
#o(n),o(n)
hashset=set以上是关于日常系列LeetCode《9·哈希查找篇》的主要内容,如果未能解决你的问题,请参考以下文章