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

三道算法题的解题思路
文档和视频讲解来自代码随想录,博主看题解后做出题目。涉及454.四数相加II、383. 赎金信、15. 三数之和三道题。四数相加II用哈希表;赎金信通过数组下标计数判断;三数之和因不能用重复元素,采用双指针法并做了优化。

文档讲解:代码随想录

视频讲解:代码随想录B站账号

状态:看了视频题解和文章解析后做出来了

454.四数相加II

class Solution:
    def fourSumCount(self, nums1: List[int], nums2: List[int], nums3: List[int], nums4: List[int]) -> int:
        res = {}
        n = len(nums1)
        count = 0

        for i in range(n):
            for j in range(n):
                total = nums1[i] + nums2[j]
                if total in res:
                    res[total] += 1
                else:
                    res[total] = 1

        for a in range(n):
            for b in range(n):
                total = nums3[a] + nums4[b]
                if 0 - total in res:
                    count += res[0 - total]
        
        return count

思路:这道题和两数之和思路完全一致,不同的就是在哈希表中添加的不是一个列表中的值,而是任意两个列表中任意两元素的和。再通过target-总和是否出现在哈希表中,将出线次数累积到结果的count变量中即可。

383. 赎金信

class Solution:
    def canConstruct(self, ransomNote: str, magazine: str) -> bool:
        alphabet = [0] * 26

        for c in ransomNote:
            alphabet[ord(c) - ord("a")] += 1

        for d in magazine:
            alphabet[ord(d) - ord("a")] -= 1

        for e in alphabet:
            if e > 0:
                return False

        return True

思路:又是似曾相识的一道题。首先定义一个长度为26的数组,遍历randomNote,将字符的相对位置的下标+1,再遍历magazine,做同样的操作但这次下标值-1。最后遍历alphabet数组,如果有大于1的情况,证明magazine里的字符无法构成ransomNote里的字符,返回False。整个列表循环下来如果还没有return,那就return True。

15. 三数之和

class Solution:
    def threeSum(self, nums: List[int]) -> List[List[int]]:
        result = []
        nums.sort()

        for i in range(len(nums)):
            if nums[i] > 0:
                return result

            if i > 0 and nums[i] == nums[i-1]:
                continue

            left = i + 1
            right = len(nums) - 1

            while left < right:
                total = nums[i] + nums[left] + nums[right]
                if total < 0:
                    left += 1
                elif total > 0:
                    right -= 1
                else:
                    result.append([nums[i], nums[left], nums[right]])
                        
                    while left < right and nums[right] == nums[right - 1]:
                            right -= 1
                    while left < right and nums[left] == nums[left + 1]:
                            left += 1

                    left += 1
                    right -= 1

        return result
            

思路:这题因为规定了不能使用重复元素,所以用哈希表的方式比较困难,转而使用双指针。

code中的i为双指针运动中唯一不变的指针,相当于固化一个指针把三指针降维到双指针,使代码更加优化。

因为已经排序了,所以如果i(也就是最左边的数)大于0,那右侧比它大的数字无论怎么加都不可能等于0,所以直接返回当前的结果result,优化了时间复杂度。

如果i>0,也就是至少遍历到第二个循环的时候,如果i的值和i-1的值相同,那说明已经把i为最左的可能性计入结果表中,所以可以直接跳过。切忌不可以判断i和i+1的值,因为这样就会忽略一些可能性。

  • 使用i和i+1来作判断,在(-1,-1,0,1)的情况下,i=1就可以直接跳过,因为i=0的时候,(-1,0,1)就已经进入结果列表了。
  • 使用i和i+1来判断,在(-1,-1,2,1)的情况下,(-1,-1,2)就会被忽略掉。

进入while循环,首先计算三数之和,如果小于0,把left往右移动一位,如果大于0,把right向左移动一位。

如果等于0,首先将结果append到结果列表中,然后为避免重复运算,将left,right会重复计算的情况用while跳过。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值