day7 哈希表 part02

454.四数相加II

题目链接:https://leetcode.cn/problems/4sum-ii/

视频链接:学透哈希表,map使用有技巧!LeetCode:454.四数相加II_哔哩哔哩_bilibili

文章链接:代码随想录

python:

(版本一)使用字典

class Solution(object):
    def fourSumCount(self, nums1, nums2, nums3, nums4):
        # 使用字典存储nums1和nums2中元素的和及其出现次数
        hashmap = dict() #创建一个空字典,即哈希表
        # 遍历nums1和nums2中的每一个元素组合,计算它们的和
        for n1 in nums1:
            for n2 in nums2:
                # 如果这个和已经在字典中,更新出现次数
                if n1 + n2 in hashmap:
                    hashmap[n1+n2] += 1
                else:
                    # 如果这个和不在字典中,初始化出现次数为1
                    hashmap[n1+n2] = 1
        
        # 初始化计数器,用于记录四元组的数量
        count = 0
        # 遍历nums3和nums4中的每一个元素组合,计算它们的和的相反数
        for n3 in nums3:
            for n4 in nums4:
                key = - n3 - n4
                # 如果相反数在之前的字典中存在,则累加相应的次数到计数器中
                if key in hashmap:
                    count += hashmap[key]
        # 返回计数器的值,即满足条件的四元组的数量
        return count

(版本二)使用字典

class Solution(object):
    def fourSumCount(self, nums1, nums2, nums3, nums4):
        # 使用字典存储nums1和nums2中元素的和及其出现次数
        hashmap = dict()
        
        # 遍历nums1和nums2中的每一个元素组合,计算它们的和
        for n1 in nums1:
            for n2 in nums2:
                # 使用字典的get方法,如果和已经存在于字典中,则取出当前值并加1,
                # 如果不存在,则使用默认值0,然后加1
                hashmap[n1 + n2] = hashmap.get(n1 + n2, 0) + 1
        
        # 初始化计数器,用于记录四元组的数量
        count = 0
        
        # 遍历nums3和nums4中的每一个元素组合,计算它们的和的相反数
        for n3 in nums3:
            for n4 in nums4:
                key = -n3 -n4
                # 如果相反数在之前的字典中存在,则累加相应的次数到计数器中
                if key in hashmap:
                    count += hashmap[key]
        
        # 返回计数器的值,即满足条件的四元组的数量
        return count

不要把循环搞错

(版本三)使用defaultdict

from collections import defaultdict

class Solution:
    def fourSumCount(self, nums1: list, nums2: list, nums3: list, nums4: list) -> int:
        # 使用 defaultdict 创建一个默认值为0的字典 rec
        # rec 用于存储 nums1 和 nums2 的元素组合的和及其出现的次数
        rec, cnt = defaultdict(lambda: 0), 0
        
        # 遍历 nums1 和 nums2 中的每一个元素组合,计算它们的和并存储到 rec 中
        for i in nums1:
            for j in nums2:
                rec[i + j] += 1  # 如果和已经存在于字典中,则值加1,否则初始化为1
        
        # 遍历 nums3 和 nums4 中的每一个元素组合,计算它们的和的相反数
        for i in nums3:
            for j in nums4:
                # 如果相反数存在于 rec 中,则累加相应的次数到 cnt 中
                cnt += rec.get(-(i + j), 0)  # 如果相反数不存在,则返回默认值0
        
        # 返回计数器的值,即满足条件的四元组数量
        return cnt

383. 赎金信

题目链接:. - 力扣(LeetCode)

文章链接:代码随想录

python:

(版本一)使用数组

class Solution:
    def canConstruct(self, ransomNote: str, magazine: str) -> bool:
        # 创建两个大小为26的列表,用于记录每个字母出现的次数
        # ransom_count记录赎金信中的字母计数
        # magazine_count记录杂志中的字母计数
        ransom_count = [0] * 26
        magazine_count = [0] * 26
        
        # 遍历赎金信中的每个字符,统计每个字母的出现次数
        for c in ransomNote:
            # 计算字符c在字母表中的位置,并更新对应位置的计数
            ransom_count[ord(c) - ord('a')] += 1  
        ord 函数用于返回一个字符的 Unicode 码点(整数表示)。这个函数接收一个字符(长度为1的字符串)作为参数,并返回它对应的整数值。
        
        # 遍历杂志中的每个字符,统计每个字母的出现次数
        for c in magazine:
            # 计算字符c在字母表中的位置,并更新对应位置的计数
            magazine_count[ord(c) - ord('a')] += 1
        
        # 检查赎金信中每个字母的数量是否都不超过杂志中对应字母的数量
        return all(ransom_count[i] <= magazine_count[i] for i in range(26))

(版本二)使用defaultdic

from collections import defaultdict

class Solution:
    def canConstruct(self, ransomNote: str, magazine: str) -> bool:
        # 使用 defaultdict 创建一个默认值为 0 的字典 hashmap
        # hashmap 用于存储杂志中每个字母出现的次数
        hashmap = defaultdict(int)

        # 遍历杂志中的每个字符,统计每个字母的出现次数
        for x in magazine:
            hashmap[x] += 1

        # 遍历赎金信中的每个字符,检查是否可以在杂志中找到足够的匹配字符
        for x in ransomNote:
            value = hashmap.get(x)
            # 如果字母 x 不在杂志中或杂志中的该字母数量不足,则返回 False
            if not value:
                return False
            else:
                # 如果字母 x 在杂志中,减少该字母的计数
                hashmap[x] -= 1

        # 如果所有字母都可以在杂志中找到足够的匹配字符,则返回 True
        return True

(版本三)使用字典

class Solution:
    def canConstruct(self, ransomNote: str, magazine: str) -> bool:
        # 创建一个字典 counts,用于存储杂志中每个字母出现的次数
        counts = {}
        
        # 遍历杂志中的每个字符,统计每个字母的出现次数
        for c in magazine:
            # 使用 get 方法获取当前字母 c 的计数值,如果不存在则返回 0,然后加 1
            counts[c] = counts.get(c, 0) + 1
        
        # 遍历赎金信中的每个字符,检查是否可以在杂志中找到足够的匹配字符
        for c in ransomNote:
            # 如果字母 c 不在 counts 字典中或 counts[c] 的值为 0
            # 则表示杂志中没有足够的字符 c,返回 False
            if c not in counts or counts[c] == 0:
                return False
            # 如果字母 c 在 counts 字典中,且 counts[c] 的值大于 0
            # 则将 counts[c] 的值减 1
            counts[c] -= 1
        
        # 如果所有字母都可以在杂志中找到足够的匹配字符,则返回 True
        return True

(版本四)使用Counter

from collections import Counter

class Solution:
    def canConstruct(self, ransomNote: str, magazine: str) -> bool:
        # 使用 Counter 创建两个计数字典,分别统计 ransomNote 和 magazine 中每个字符出现的次数
        ransom_counter = Counter(ransomNote)
        magazine_counter = Counter(magazine)
        
        # 检查 ransom_counter 是否是 magazine_counter 的子集
        # 即检查 magazine 中是否有足够的字符来构建 ransomNote
        return not ransom_counter - magazine_counter

(版本五)使用count

class Solution:
    def canConstruct(self, ransomNote: str, magazine: str) -> bool:
        # 使用 all() 函数和生成器表达式来检查 ransomNote 中的每个字符
        # 对于每个字符 c,比较 ransomNote 中字符 c 的计数和 magazine 中字符 c 的计数
        # 如果 ransomNote 中的所有字符的计数都小于或等于 magazine 中的相应字符的计数,则返回 True
        return all(ransomNote.count(c) <= magazine.count(c) for c in set(ransomNote))

(版本六)使用count(简单易懂)

class Solution:
    def canConstruct(self, ransomNote: str, magazine: str) -> bool:
        # 遍历 ransomNote 中的每个字符
        for char in ransomNote:
            # 检查该字符是否在 magazine 中,并且其在 ransomNote 中的计数是否小于等于其在 magazine 中的计数
            if char in magazine and ransomNote.count(char) <= magazine.count(char):
                continue
            else:
                # 如果上述条件不满足,则返回 False
                return False
        # 如果所有字符都满足条件,则返回 True
        return True

15. 三数之和

题目链接:. - 力扣(LeetCode)

视频链接:梦破碎的地方!| LeetCode:15.三数之和_哔哩哔哩_bilibili

文章链接:代码随想录

python:

(版本一)双指针

class Solution:
    def threeSum(self, nums: List[int]) -> List[List[int]]:
        result = []  # 存储结果的列表
        nums.sort()  # 对数组进行排序
        
        # 遍历数组中的每个元素
        for i in range(len(nums)): 
        #一个遍历列表 nums 的循环结构,它会生成从 0 到 len(nums) - 1 的索引。
            # 如果当前元素已经大于0,后续元素也都大于0,不可能组成和为零的三元组
            if nums[i] > 0:
                return result
            
            # 跳过重复元素以避免重复三元组
            if i > 0 and nums[i] == nums[i - 1]:
                continue
            
            left = i + 1  # 左指针
            right = len(nums) - 1  # 右指针
            
            # 使用双指针查找和为零的三元组
            while right > left:
                sum_ = nums[i] + nums[left] + nums[right]  # 计算三元组的和
                
                if sum_ < 0:
                    left += 1  # 如果和小于0,移动左指针以增加和
                elif sum_ > 0:
                    right -= 1  # 如果和大于0,移动右指针以减少和
                else:
                    result.append([nums[i], nums[left], nums[right]])  # 找到和为零的三元组,加入结果列表
                    
                    # 跳过重复元素以避免重复三元组
                    while right > left and nums[right] == nums[right - 1]:
                        right -= 1
                    while right > left and nums[left] == nums[left + 1]:
                        left += 1
                        
                    right -= 1  # 移动右指针
                    left += 1  # 移动左指针
                    
        return result  # 返回所有和为零的三元组

(版本二)使用字典

class Solution:
    def threeSum(self, nums: List[int]) -> List[List[int]]:
        result = []
        nums.sort()  # 首先对数组进行排序

        # 找出a + b + c = 0的三元组
        # a = nums[i], b = nums[j], c = -(a + b)
        for i in range(len(nums)):
            # 排序之后如果第一个元素已经大于零,那么不可能凑成三元组
            if nums[i] > 0:
                break  # 因为数组已经排序,后面的数也会大于零

            # 三元组元素a去重
            if i > 0 and nums[i] == nums[i - 1]:
                continue

            # 使用字典存储两数之和
            d = {}
            for j in range(i + 1, len(nums)):
                # 三元组元素b去重
                if j > i + 2 and nums[j] == nums[j-1] == nums[j-2]:
                    continue

                c = 0 - (nums[i] + nums[j])  # 计算c使得a + b + c = 0
                if c in d:
                    # 找到一组满足条件的三元组
                    result.append([nums[i], nums[j], c])
                    d.pop(c)  # 三元组元素c去重
                else:
                    d[nums[j]] = j  # 记录nums[j]的位置

        return result

18. 四数之和

题目链接:. - 力扣(LeetCode)

视频链接:难在去重和剪枝!| LeetCode:18. 四数之和_哔哩哔哩_bilibili

文章链接:代码随想录

python:

(版本一)双指针

class Solution:
    def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
        nums.sort()  # 首先对数组进行排序
        n = len(nums)
        result = []

        # 遍历数组,选定第一个元素
        for i in range(n):
            # 剪枝优化:如果当前元素大于目标值,并且目标值大于0,则后续元素无法组成四元组
            if nums[i] > target and nums[i] > 0 and target > 0:
                break

            # 去重:跳过重复元素
            if i > 0 and nums[i] == nums[i-1]:
                continue

            # 遍历数组,选定第二个元素
            for j in range(i+1, n):
                # 剪枝优化:如果当前两个元素之和大于目标值,并且目标值大于0,则后续元素无法组成四元组
                if nums[i] + nums[j] > target and target > 0:
                    break

                # 去重:跳过重复元素
                if j > i+1 and nums[j] == nums[j-1]:
                    continue

                left, right = j+1, n-1  # 初始化双指针
                while left < right:
                    s = nums[i] + nums[j] + nums[left] + nums[right]  # 计算四数之和

                    if s == target:
                        # 找到一个四元组,加入结果集
                        result.append([nums[i], nums[j], nums[left], nums[right]])

                        # 去重:跳过重复的第三个元素
                        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  # 移动右指针
                    elif s < target:
                        left += 1  # 如果当前和小于目标值,移动左指针增加和
                    else:
                        right -= 1  # 如果当前和大于目标值,移动右指针减小和

        return result  # 返回所有符合条件的四元组

(版本二)使用字典

class Solution(object):
    def fourSum(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: List[List[int]]
        """
        # 创建一个字典来存储输入列表中每个数字的频率
        freq = {}
        for num in nums:
            freq[num] = freq.get(num, 0) + 1
        
        # 创建一个集合来存储最终答案,并遍历4个数字的所有唯一组合
        ans = set()
        for i in range(len(nums)):
            for j in range(i + 1, len(nums)):
                for k in range(j + 1, len(nums)):
                    # 计算第四个数的值,使得四数之和等于目标值
                    val = target - (nums[i] + nums[j] + nums[k])
                    if val in freq:
                        # 确保没有重复,计算val在当前组合中的出现次数
                        count = (nums[i] == val) + (nums[j] == val) + (nums[k] == val)
                        if freq[val] > count:
                            # 将满足条件的四元组加入集合,并进行排序以避免重复
                            ans.add(tuple(sorted([nums[i], nums[j], nums[k], val])))
        
        # 将集合中的四元组转换为列表并返回
        return [list(x) for x in ans]

  • 6
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值