代码随想录算法训练营第七天| 454.四数相加II、383. 赎金信、15. 三数之和、18. 四数之和

454.四数相加II

思路

和昨天的两数之和类似。

  1. 遍历前两个数组,统计两个数组元素之和,和出现的次数,放到map中。key放a和b两数之和,value放a和b两数之和出现的次数。
  2. 遍历后两个数组,找到如果 0-(c+d) 在map中出现过的话,就用count把map中key对应的value也就是出现次数统计出来。

代码

class Solution:
    def fourSumCount(self, nums1: List[int], nums2: List[int], nums3: List[int], nums4: List[int]) -> int:
        hashmap = dict()
        for i in nums1:
            for j in nums2:
                hashmap[i+j] = hashmap.get(i+j, 0) + 1

        count = 0
        for i in nums3:
            for j in nums4:
                count += hashmap.get(-i-j, 0)

        return count

383. 赎金信

思路

与昨天的前两题思路相似。
在本题的情况下,使用map的空间消耗要比数组大一些,因为map要维护红黑树或者哈希表,而且还要做哈希函数,是费时的。数据量大的话就能体现出来差别了。 所以数组更加简单直接有效。

代码

数组法

class Solution:
    def canConstruct(self, ransomNote: str, magazine: str) -> bool:
        ransom_count = [0] * 26
        magazine_count = [0] * 26
        for c in ransomNote:
            ransom_count[ord(c) - ord('a')] += 1
        for c in magazine:
            magazine_count[ord(c) - ord('a')] += 1
        return all(ransom_count[i] <= magazine_count[i] for i in range(26))

哈希表法

class Solution:
    def canConstruct(self, ransomNote: str, magazine: str) -> bool:
        hashmap = dict()
        for s in magazine:
            hashmap[s] = hashmap.get(s, 0) + 1

        for ss in ransomNote:
            if hashmap.get(ss, 0) > 0:
                hashmap[ss] = hashmap.get(ss) - 1
            else:
                return False
        return True

Counter法

from collections import Counter

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

15. 三数之和

思路

  1. 题目中说不可以包含重复的三元组。用哈希法找到所有符合条件的三元组再去重是非常费时的。
  2. 用双指针法,首先将数组排序。然后有一层for循环,i从下标0的地方开始,同时定一个下标left定义在i+1的位置上,定义下标right在数组结尾的位置上。找nums[i]+nums[left]+nums[right]=0。如果nums[i] + nums[left] + nums[right] > 0就说明 此时三数之和大了,所以right下标就应该向左移动;如果 nums[i] + nums[left] + nums[right] < 0说明此时三数之和小了,left 就向右移动,直到left与right相遇为止。
  3. a, b, c都要去重,详见代码。

代码

class Solution:
    def threeSum(self, nums: List[int]) -> List[List[int]]:
        result = []
        nums.sort()
        
        for i in range(len(nums)):
            # 如果第一个元素已经大于0,不需要进一步检查
            if nums[i] > 0:
                return result
            
            # 跳过相同的元素以避免重复
            # 不能有重复的三元组,但三元组内的元素是可以重复的,所以与i-1比较
            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
                elif sum_ > 0:
                    right -= 1
                else:
                    result.append([nums[i], nums[left], nums[right]])
                    # 要先保存一个,再进行后面的去重判断,考虑列表元素都是0的情况
                    
                    # 跳过相同的元素以避免重复
                    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

18. 四数之和

思路

和上一题是一个思路,都是使用双指针法, 只不过是在上一题的基础上再套一层for循环。但在剪枝时不能只看是否大于target,因为target有可能是负数,要想剪枝需要添加一些限定条件。

代码

class Solution:
    def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
        nums.sort()
        n = len(nums)
        result = []
        for i in range(n):
            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):
                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

每日总结

前两个题是跟昨天类似的,后两个双指针的思路稍微复杂一些,要认真练习写一下。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值