【日常系列】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
【计算之魂 11章】

class Solution:
    def longestConsecutive(self, nums: List[int]) -> int:
        # 需去重,不然错误
        nums = set(nums)
        # 第一遍遍历,获取最长连续子序列
        # lastLen[i]:最后一个元素是 i 的连续序列的最大长度
        lastLen = {}
        for i, x in enumerate(nums):
            if x - 1 in lastLen:
                new_len = lastLen[x-1] + 1
                del lastLen[x-1]
                lastLen[x] = new_len
            else:
                lastLen[x] = 1

        # 第二遍遍历,合并连续序列
        maxLen = 0 if not lastLen else max(lastLen.values())
        for i in lastLen:
            while i - lastLen[i] in lastLen:
                lastLen[i] += lastLen[i - lastLen[i]]
                # del lastLen[i - lastLen[i]]
                if lastLen[i] > maxLen:
                    maxLen = lastLen[i]
        return maxLen
        

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(nums)
        for i in range(1,len(nums)+1):
            if not i in hashset:return i
        return len(nums)+1     
#方案二:优化-常数空间(标记) 
class Solution:
    def firstMissingPositive(self, nums: List[int]) -> int:
        #o(1),o(n)
        n=len(nums)
        #①key:非正数不予考虑(意味着某些正数的缺失)
        #需要在正数中寻找缺失值
        for i in range(n):
            if nums[i]<=0:nums[i]=n+1#key:要不影响结果
        
        #---->>>>全部转正数   

        #②key:标记
        #(正数-1)对应索引值变负
        for i in range(n):
            num = abs(nums[i]) #key:注意其索引值也要找对应标记
            if (num <= n):
                nums[num - 1] = -abs(nums[num - 1])
        #③
        for i in range(n):
            if nums[i]>0:return i+1
        return n+1        

lc 1122 【剑指 075】:数组的相对排序
https://leetcode.cn/problems/relative-sort-array/
提示:
1 <= arr1.length, arr2.length <= 1000
0 <= arr1[i], arr2[i] <= 1000
arr2 中的元素 arr2[i] 各不相同
arr2 中的每个元素 arr2[i] 都出现在 arr1 中

#方案一:自定义排序
'''
对于cmp(x,y):
如果想要x排在y前面那么返回一个负数,如果想x排在y后面那么返回一个正数
'''
class Solution:
    def relativeSortArray(self, arr1: List[int], arr2: List[int]) -> List[int]:
        #
        num_index_map={x:i for i,x in enumerate(arr2)}
        def mycmp(x:int)->(int,int):
            return (0,num_index_map[x]) if x in arr2 else (1,x) #默认以x在arr1中的索引排序;否则,以x排序。
        #
        arr1.sort(key=mycmp)
        return arr1

#方案二:计数排序
class Solution:
    def relativeSortArray(self, arr1: List[int], arr2: List[int]) -> List[int]:
        #o(1001):计数
        cnt=[0]*1001
        for arr in arr1:cnt[arr]+=1
        #  o(1001*m)
        index=0
        for arr in arr2:       
            for i in range(cnt[arr]):
                arr1[index]=arr
                index+=1
            cnt[arr]=0 #key:方便未在 arr2 中出现过的元素需要按照升序放在 arr1 的末尾
        #
        for i in range(1001):
            for j in range(cnt[i]):
                arr1[index]=i
                index+=1
        return arr1
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值