✅DAY 7 HashTable | 454. 四数相加 II | 383. 赎金信 | 15. 三数之和 | 18. 四数之和

 454. 四数相加 II

解题思路:nums1[i] + nums2[j] + nums3[k] + nums4[l] = 0 --> 

                  nums1[i] + nums2[j] = -  nums3[k] - nums4[l]

时间复杂度:O(n²),其中 n 是每个数组的长度。遍历了 nums1 和 nums2 来计算哈希表中的值组合,接着遍历了 nums3 和 nums4 来查找组合。

空间复杂度:O(n²),哈希表中最多会存储 n² 个 n1 + n2 的组合。

class Solution:
    def fourSumCount(self, nums1: List[int], nums2: List[int], nums3: List[int], nums4: List[int]) -> int:
        hashTable = dict()

        for n1 in nums1:
            for n2 in nums2:
                hashTable[n1+n2] = hashTable.get(n1+n2, 0) + 1
        count = 0
        for n3 in nums3:
            for n4 in nums4:
                # n3+n4 = -(n1+n2)
                key = -(n3+n4)
                if key in hashTable:
                    count += hashTable[key]
        return count

解题思路:使用defaultdict

使用 defaultdict:

• hashMap = defaultdict(int):创建一个 defaultdict,当访问的键不存在时,它会自动初始化为 0。

• 简化了 hashMap.get(sum12, 0) + 1 的操作,只需要直接执行 hashMap[sum12] += 1。

from collections import defaultdict
class Solution:
    def fourSumCount(self, nums1: List[int], nums2: List[int], nums3: List[int], nums4: List[int]) -> int:
        # 使用 defaultdict 初始化
        hashMap = defaultdict(int)
        # 遍历 nums1 和 nums2,计算它们的和并记录在哈希表中
        for n1 in nums1:
            for n2 in nums2:
                sum12 = n1 + n2
                hashMap[sum12] += 1  # 直接增加值
        count = 0  
        # 遍历 nums3 和 nums4,查找 -(n3 + n4) 是否存在于哈希表中
        for n3 in nums3:
            for n4 in nums4:
                sum34 = -(n3 + n4)
                if sum34 in hashMap:
                    count += hashMap[sum34]  # 累加哈希表中的值
        return count

383. 赎金信

解题思路:用hashtable解法

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

        for char in magazine:
            hashmap[char] = hashmap.get(char,0) +1
        
        for char in ransomNote:
            # if char in hashmap:
            #     hashmap[char]-=1
            #     if hashmap[char] == 0:
            #         del hashmap[char]
            # else:
            #     return False
            if char not in hashmap or hashmap[char] == 0:
                 return False
            hashmap[char] -= 1 
        return True

解题思路:collections.Counter

**减法操作 Counter(ransomNote) - Counter(magazine):

• Counter 的减法会计算两个 Counter 之间的差异。它会从 ransomNote 中每个字符的计数中减去 magazine 中对应字符的计数。

时间复杂度:O(n + m),其中 n 和 m 分别是 ransomNote 和 magazine 的长度。Counter 会遍历这两个字符串来统计字符的出现次数。

空间复杂度:O(k),其中 k是ransomNote和magazine 中不同字符的数量。

from collections import Counter

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

15. 三数之和

解题思路:双指针解法。需先将数据排序,后根据左右大小进行移动,小了往右大了往左,同时需跳过重复值。

排序的时间复杂度:O(n log n),其中 n 是数组的长度。

双指针的时间复杂度:外层循环是 O(n),内层双指针操作最多也是 O(n),因此双指针部分的时间复杂度为 O(n²)。

总时间复杂度:O(n²)。

class Solution:
    def threeSum(self, nums: List[int]) -> List[List[int]]:
        # 首先将数组排序,这样可以使用双指针技巧来优化查找
        nums.sort()
        result = []

        # 遍历每个元素,尝试固定一个元素,然后查找其后的两个元素
        for i in range(len(nums)):
            # 如果当前元素大于 0,说明后续的所有元素也都会大于 0
            # 因为数组已经排序好,不可能再找到三个数的和为 0,提前退出
            if nums[i] > 0:
                break  # 优化:减少不必要的检查
            
            # 跳过重复的元素,避免结果中出现重复的组合
            if i > 0 and nums[i] == nums[i - 1]:
                continue  # 优化:避免重复解
            
            # 使用双指针在 nums[i] 之后的数组中查找和为 0 的另外两个数
            left, right = i + 1, len(nums) - 1

            # 双指针查找
            while left < right:
                curSum = nums[i] + nums[left] + nums[right]

                if curSum < 0:
                    left += 1  # 如果和小于 0,说明需要更大的数,将左指针右移
                elif curSum > 0:
                    right -= 1  # 如果和大于 0,说明需要更小的数,将右指针左移
                else:
                    # 找到一个解,加入结果
                    result.append([nums[i], 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

        return result

解题思路:在遍历过程中跳过重复的元素,确保相同的组合只被计入一次。使用集合 (set) 来存储结果,因为集合可以自动去除重复的元素。

时间复杂度:O(n²),因为对于每个元素,内层遍历需要 O(n) 时间。

空间复杂度:O(n),用于存储集合和哈希表。

class Solution:
    def threeSum(self, nums: List[int]) -> List[List[int]]:
        nums.sort()
        result = set()
        for i in range(len(nums)):
            if i > 0 and nums[i] == nums[i-1]:
                continue
            seen = set()
            for j in range(i+1, len(nums)):
                complement = - nums[i] - nums[j]
                if complement in seen:
                    result.add((nums[i], nums[j], complement))
                    while j + 1 < len(nums) and nums[j] == nums[j+1]:
                        j += 1
                seen.add(nums[j])
        # 将 result 中的所有元素从一种数据类型(通常是元组 tuple)转换为列表 list
        return list(map(list,result))

18. 四数之和

解题思路:逻辑一致,就是复杂度比较高,loop套loop+双指针逻辑

class Solution:
    def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
        # 结果存放所有满足条件的四元组
        result = []
        nums.sort()  # 先对数组进行排序,便于后面的双指针操作
        
        # 第一层循环:枚举第一个数字
        for i in range(len(nums) - 3):
            # 跳过重复的元素,避免重复结果
            if i > 0 and nums[i] == nums[i - 1]:
                continue
                
            # 第二层循环:枚举第二个数字
            for j in range(i + 1, len(nums) - 2):
                # 跳过重复的元素
                if j > i + 1 and nums[j] == nums[j - 1]:
                    continue
                    
                # 双指针查找剩下的两个数字
                left, right = j + 1, len(nums) - 1
                while left < right:
                    cur_sum = nums[i] + nums[j] + nums[left] + nums[right]
                    
                    if cur_sum == 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 cur_sum < target:
                        # 当前和小于目标值,移动左指针使和变大
                        left += 1
                    else:
                        # 当前和大于目标值,移动右指针使和变小
                        right -= 1
        
        return result
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值