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

454.四数相加II

暴力解法:四重循环;或者一个哈希表,然后三重循环

看了解题思路之后:两个两重循环,先统计两个数组的和及其出现次数,然后再循环另外两个数组

class Solution:
    def fourSumCount(self, nums1: List[int], nums2: List[int], nums3: List[int], nums4: List[int]) -> int:
        from collections import defaultdict
        sum_12 = defaultdict(int)
        for i in nums1:
            for j in nums2:
                sum_12[i+j] += 1

        count = 0
        for i in nums3:
            for j in nums4:
                key = 0 - i - j
                if key in sum_12:
                    count += sum_12[key]

        return count

383. 赎金信

注意点:magazine中每个字符只能使用一次,所以每次使用后需要减一

使用哈希表统计magazine的字符及出现次数,然后遍历ransomNote

class Solution:
    def canConstruct(self, ransomNote: str, magazine: str) -> bool:
        from collections import defaultdict
        temp = defaultdict(int)
        for i in magazine:
            temp[i] += 1
        for i in ransomNote:
            if i not in temp:
                return False
            if temp[i] <= 0:
                return False
            temp[i] -= 1
        return True

看了题解之后,可以使用数组,因为两个字符串都是由小写字母组成

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
            if record[ord(i) - ord('a')] < 0:
                return False
        return True

15. 三数之和

注意点:不可以包含重复的三元组,除了索引不能相同,还有就是结果中的多个三元组也不能重复,这种情况导致了题目复杂度增加

看了题解之后,了解了双指针法。因为本题是返回数组元素,不是索引值,所以可以排序使用双指针法

python小知识:nums.sort()为原地排序

class Solution:
    def threeSum(self, nums: List[int]) -> List[List[int]]:
        # 因为最后返回的是元素,可以进行排序,然后使用双指针
        res = []
        nums.sort()
        for i in range(len(nums)):
            if nums[i] > 0:  # 已经进行排序了,如果当前最小的值都>0了,后续不可能有三个值相加为0的
                break
            if i > 0 and nums[i] == nums[i-1]:  # 对a进行去重;如果a前面的数值和a相等,那么b+c=-a等组合已经寻找过了,没有必要再来一次
                continue
            left = i+1
            right = len(nums) - 1
            while left < right:  # 因为索引不能相同,left==right是没有用的
                if nums[left] + nums[right] + nums[i] > 0:
                    right -= 1
                elif nums[left] + nums[right] + nums[i] < 0:
                    left += 1
                else:
                    res.append([nums[i], nums[left], nums[right]])
                    # 对b和c去重
                    while left < right and nums[left] == nums[left+1]:
                        left += 1
                    while left < right and nums[right] == nums[right-1]:
                        right -= 1
                    # =0后left和right都需要移动一步
                    left += 1
                    right -= 1
        return res

18. 四数之和

四数之和与三数之和思路是一样的,三数之和是一层循环+双指针,四数之和是两层循环+双指针

题目中有个地方有差异,三数之和是等于0,四数之和是等于target,这个会导致剪枝的条件不同

从四数之和可以更好的理解三数之和的剪枝和去重操作

class Solution:
    def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
        res = []
        # 因为要使用双指针,先排序
        nums.sort()
        # 使用双重循环+双指针
        for i in range(len(nums)):
            # 第一重循环 剪枝
            if nums[i] > target and nums[i] >= 0:
                break
            # 第一重循环 去重
            if i > 0 and nums[i] == nums[i-1]:
                continue

            for j in range(i+1, len(nums)):
                # 第二重循环 剪枝
                if nums[i] + nums[j] > target and nums[j] >= 0:
                    break
                # 第二重循环 去重,需要注意是j>i+1而不是j>0,因为只需要和在此次循环中遍历过的j进行比较
                if j > i+1 and nums[j] == nums[j-1]:
                    continue

                # 双指针过程开始
                left = j + 1
                right = len(nums) - 1
                while left < right:
                    sum = nums[i] + nums[j] + nums[left] + nums[right]
                    if sum > target:
                        right -= 1
                    elif sum < target:
                        left += 1
                    else:
                        res.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
        return res

你可能感兴趣的:(数据结构)