算法记录 | Day6哈希表基础Ⅱ

97 阅读4分钟

算法记录 | Day6哈希表基础Ⅱ

LeetCode 454-四数相加Ⅱ

题目描述:给你四个整数数组 nums1、nums2、nums3 和 nums4 ,数组长度都是 n ,请你计算有多少个元组 (i, j, k, l) 能满足:

0 <= i, j, k, l < n nums1[i] + nums2[j] + nums3[k] + nums4[l] == 0

输入:nums1 = [1,2], nums2 = [-2,-1], nums3 = [-1,2], nums4 = [0,2]
输出:2
解释:
两个元组如下:
1. (0, 0, 0, 1) -> nums1[0] + nums2[0] + nums3[0] + nums4[1] = 1 + (-2) + (-1) + 2 = 0
2. (1, 1, 0, 0) -> nums1[1] + nums2[1] + nums3[0] + nums4[0] = 2 + (-1) + (-1) + 0 = 0

题目链接:leetcode.cn/problems/4s…

解题思路
  • 没什么思路的题,只知道暴力解法,所以看了题解之后才知道的
class Solution:
    def fourSumCount(self, nums1: List[int], nums2: List[int], nums3: List[int], nums4: List[int]) -> int:
        # a + b + c + d = 0
        # (a+b) + (c+d) = 0
        n = len(nums1)

        # a+b 的结果
        hash_ab = dict()
        for i in range(n):
            for j in range(n):
                res = nums1[i] + nums2[j]
                if res not in hash_ab:
                    hash_ab[res] = 1
                else:
                    hash_ab[res] += 1
        print(hash_ab)
        
        # c+d 的结果
        # 这里统计count,知道元组有多少个
        count = 0
        for n3 in nums3:
            for n4 in nums4:
                key = - n3 - n4
                if key in hash_ab:
                    count += hash_ab[key]
        return count
       

注意:

记录次数之后,找key值的时候要加次数。自己写第一遍的时候发现了不记录次数的话,每次只能count+1,会漏掉值相等的一种情况。

难点
  • 如何思考题解是将ab相加,找bc的过程,看数学敏感度么。。
总结

hash表可用来记录次数


LeetCode 383-救赎金

给你两个字符串:ransomNote 和 magazine ,判断 ransomNote 能不能由 magazine 里面的字符构成。

如果可以,返回 true ;否则返回 false

magazine 中的每个字符只能在 ransomNote 中使用一次。

题目链接:leetcode.cn/problems/ra…

输入:ransomNote = "a", magazine = "b"
输出:false
解题思路
  • 我的写法
class Solution:
    def canConstruct(self, ransomNote: str, magazine: str) -> bool:
        # 这题究竟是包含字母一样就行,还是顺序也要一样?aa 和 aba正确么?
        # 先按照包含字母一样即可做
        hashmap = dict()
        for i in magazine:
            if i not in hashmap:
                hashmap[i] = 1
            else:
                hashmap[i] += 1
        
        for i in ransomNote:
            if i not in hashmap:
                return False
            if i in hashmap:
                hashmap[i] -= 1
        
        for j in hashmap:
            if hashmap[j] < 0:
                return False
        return True

注意

  • 理解题意

写法二:

class Solution:
    def canConstruct(self, ransomNote: str, magazine: str) -> bool:

        arr = [0] * 26

        for x in magazine:
            arr[ord(x) - ord('a')] += 1

        for x in ransomNote:
            if arr[ord(x) - ord('a')] == 0:
                return False
            else:
                arr[ord(x) - ord('a')] -= 1
        
        return True

写法三:

class Solution:
    def canConstruct(self, ransomNote: str, magazine: str) -> bool:
        c1 = collections.Counter(ransomNote)
        c2 = collections.Counter(magazine)
        x = c1 - c2
        #x只保留值大于0的符号,当c1里面的符号个数小于c2时,不会被保留
        #所以x只保留下了,magazine不能表达的
        if(len(x)==0):
            return True
        else:
            return False

注意:这个Counter的用法就比较神奇了。

  • 哈希表在python中可以用collections.Counter计数来体现。该方法用于统计某序列中每个元素出现的次数,以键值对的方式存在字典中。但类型其实是Counter。
难点
  • 多种写法,第二种和第三种写使用的时候都不太熟悉
总结

LeetCode 15-三数之和

题目描述:给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != ji != kj != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请

你返回所有和为 0 且不重复的三元组。

注意:答案中不可以包含重复的三元组。

题目链接:leetcode.cn/problems/3s…

输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]
解释:
nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0 。
nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0 。
nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0 。
不同的三元组是 [-1,0,1] 和 [-1,-1,2] 。
注意,输出的顺序和三元组的顺序并不重要。
解题思路
  • 双指针法
class Solution:
    def threeSum(self, nums: List[int]) -> List[List[int]]:
        # a + b + c = 0
        n = len(nums)
        res = []
        # 先排序
        nums.sort()

        for a in range(n):
            if nums[a] > 0:
                return res
            # 去重
            if a>0 and nums[a] == nums[a-1]:
                continue
            left = a + 1
            right = n - 1

            while left < right:
                total = nums[a] + nums[left] + nums[right]

                if total > 0:
                    right -= 1
                elif total < 0:
                    left += 1
                else:
                    res.append([nums[a],nums[left],nums[right]])
                    # 去重 # 这里最开始写成了if,还是会出现重复错误
                    while left < right and nums[left] == nums[left+1]:
                        left += 1
                    while left < right and nums[right] == nums[right-1]:
                        right -= 1
                    left += 1
                    right -= 1
            
        return res
难点
  • 双指针法
  • 去重操作
总结

暂时可以先记住这种解法,三个数的和,三个数的集合如何写


LeetCode 18-四数之和

题目描述:给你一个由 n 个整数组成的数组 nums ,和一个目标值 target 。请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], nums[b], nums[c], nums[d]] (若两个四元组元素一一对应,则认为两个四元组重复):

0 <= a, b, c, d < n a、b、c 和 d 互不相同 nums[a] + nums[b] + nums[c] + nums[d] == target 你可以按 任意顺序 返回答案 。

题目链接:leetcode.cn/problems/4s…

输入:nums = [1,0,-1,0,-2,2], target = 0
输出:[[-2,-1,1,2],[-2,0,0,2],[-1,0,0,1]]
解题思路
  • 三数之和的基础上,继续加上一个for循环
class Solution:
    def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
        # 三数之和的基础上再加for循环,去重
        n = len(nums)
        nums.sort()
        res = []

        for i in range(n):
            # 去重的操作
            if i > 0 and nums[i] == nums[i-1]:
                continue
            for k in range(i+1, n):
                if k > i + 1 and nums[k] == nums[k-1]:
                    continue
                ## 双指针法
                p = k + 1
                q = n - 1
            
                while p < q:
                    if nums[i] + nums[k] + nums[p] + nums[q] > target:
                        q = q -1
                    elif nums[i] + nums[k] + nums[p] + nums[q] < target:
                        p = p + 1
                    else:
                        res.append([nums[i], nums[k], nums[p], nums[q]])
                        # 对q和p去重
                        while p < q and nums[p] == nums[p+1]: p += 1
                        while p < q and nums[q] == nums[q-1]: q -= 1
                        p += 1
                        q -= 1
        return res

注意

  • 三数之和的题解与四数之和差不多,但是如果下面还有五个数、六个数就不太适用了,这个时候要考虑其他解法
  • 四数之和与四数相加的不同点:四数相加没有要求去重,而且只需要统计次数。但四数之和这道题一定要去重才行。
难点
  • 双指针法的使用
总结

最后两题是利用双指针法,没有使用哈希表,也是区别于第一道题的思路。这些题还是经常回顾看看写写,了解的基础上加记忆,要了解去重的过程。