日常系列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·哈希查找篇》的主要内容,如果未能解决你的问题,请参考以下文章

日常系列LeetCode《1·数组常用技巧篇》

日常系列LeetCode《13·综合应用1篇》

日常系列LeetCode《2·一维数组篇》

日常系列LeetCode《5·数学篇》

日常系列LeetCode《10·栈和队列篇》

日常系列LeetCode《4·字符串篇》