力扣算法打卡第七天(链表) | 454. 四数相加 II、383. 赎金信、15. 三数之和、18. 四数之和

454. 四数相加 II

题目链接:力扣454
思路:哈希表

本题仅仅是四个数组里的元素值相加等于0,不需要考虑元素数值或下标重复的情况,类似于两数之和。
用变量cnt存储最终符合的元组个数,变量record为哈希表。
两层for循环扫描L1和L2,用key存储每一项L1+L2的数值,用value存储该数值出现次数。
两层for循环扫描L3和L4,在map中寻找对应的-(L3+L4),找到后令cnt加上该项的value值。

class Solution:
    def fourSumCount(self, nums1: List[int], nums2: List[int], nums3: List[int], nums4: List[int]) -> int:
        record = {}
        cnt = 0
        
        for i in nums1:
            for j in nums2:
                if i+j in record.keys():
                    record[i+j] += 1
                else:
                    record[i+j] = 1

        for i in nums3:
            for j in nums4:
                target = 0-i-j
                if target in record.keys():
                    cnt += record[target]
        return cnt

383. 赎金信

题目链接:力扣383
思路:哈希表

class Solution:
    def canConstruct(self, ransomNote: str, magazine: str) -> bool:
        record = [0]*26
        for i in magazine:
            record[ord(i) - ord('a')] += 1
        for i in ransomNote:
            record[ord(i) - ord('a')] -= 1
        for i in record:
            if i < 0:
                return False
        return True
            

15. 三数之和

题目链接:力扣15
思路:双指针

本题需要考虑元组重复的情况,比如[-1,0,1]和[0,1,-1]算一个三元组,使用哈希表较为麻烦,使用双指针。
双指针大体流程:
①先对数组排序。
②进入for循环:
i在数组下标0处,设置好左右指针。
最终三元组为[ nums[i], nums[left], nums[right] ],这里简写为(a,b,c)。

用for循环用来固定三元组第一个元素,左右指针用于寻找能满足相加等于0的后两个元素

需要先对a去重,检查i前面一个元素是否与当前相同,相同则continue

判断nums[i] + nums[left] + nums[right]大小,若大于0,说明该三元组“小”了,左指针向右移动,使三元组和变小
若大于0,向左移动右指针。
在这里插入图片描述
最后直至三元组之和为0(如下),或者left>=right结束当前while循环,i++进入下一次for循环。
此时收割结果,[-3, 1, 2]放入res数组中。
在这里插入图片描述
③同时,需要对left和right去重,因为在当前for循环,当前i的值下,left和right对应的数组元素值已经“用过了”,需要left和right分别向右向左走实现去重=,去重后如下。
在这里插入图片描述

去重的原因是题目要求三元组不能重复,一个三元组只能出现一次。
以左指针为例,这里去重本质上就是让左指针走到最靠右的,与之前元素值相同的位置处

同时,若本次while若找到目标,无论前面是否需要去重,左右指针还需再收缩一次。
在示例中收缩完后left>right,while结束,进入下一次for循环。
在这里插入图片描述

# 涉及到去重操作,哈希表较为麻烦,使用双指针
# 答案格式为数组元素组成的三元组(a,b,c)
class Solution:
    def threeSum(self, nums: List[int]) -> List[List[int]]:
        nums.sort()
        res=[]
        for i in range(len(nums)):
            if nums[i] > 0:
                break
            if i>0 and nums[i] == nums[i-1]:  # 三元组a去重
                continue
            left = i+1
            right = len(nums)-1
            while left < right:
                if nums[i] + nums[left] + nums[right] < 0:  # 说明当前三元组“小”了
                    left += 1
                elif nums[i] + nums[left] + nums[right] > 0:  # 说明当前三元组“大”了
                    right -= 1
                else:  #满足条件时
                    res.append([nums[i], nums[left], nums[right]])
                    while left < right and nums[left] == nums[left+1]:  #b去重,注意这里仍要保证left<right
                        left += 1
                    while left < right and nums[right] == nums[right-1]:  #c去重
                        right -= 1
                    # 找到答案后双指针在去重完后需要收缩一次
                    right -= 1
                    left +=1
        return res

18. 四数之和

题目链接:力扣18
思路:双指针

与上一题思路类似,又套一层for循环而已,两层for循环分别固定四数之和里的前两个数。
注意k和i的去重。
注意k大于target时的剪枝。

class Solution:
    def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
        nums.sort()
        res = []
        for k in range(len(nums)):
            if nums[k]>target and nums[k]>0 and target>0:
                break
            if k>0 and nums[k] == nums[k-1]:
                continue
            for i in range(k+1, len(nums)):
                if i>k+1 and nums[i] == nums[i-1]:  # 注意这里的条件,i-1不能影响到k的取值,所以要i>k+1
                    continue
                left = i+1
                right = len(nums)-1
                while left < right:
                    total = nums[k]+nums[i]+nums[left]+nums[right]
                    if total>target:
                        right -= 1
                    elif total<target:
                        left += 1
                    else:
                        res.append([nums[k], 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 res


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值