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

121 阅读2分钟

454. 四数相加 II - 力扣(LeetCode)

1. 文章链接

代码随想录 (programmercarl.com)

2. 看到题目的第一想法

来自四个数组的四个元素相加等于0, 找这四个元素分别在这四个数组的下角标。

数组长度都为200以内,所以O(n2)O(n^2)也可以。 那我们前两个元素就用for循环来搜,得到前两个元素的和s1s_1

然后剩下的一定是0s10-s_1

于是我们可以为后面这两个元素做一个长n2n^2的字典,键=两个元素的和,值为两个元素的下角标组成的列表。

但是这里有个问题就是两个元素的和可能相同,但是角标列表不一致。

3. 看完代码随想录之后的想法

我们要明确我们的目标,不是要输出四个角标组成的元组。

而是要返回总共有多少个元组,所以我们的value其实就可以存有多少种不一致的角标列表就可以,而不是直接存角标列表。

4. 实现过程中遇到的困难

碰到hash table的问题,python果断用dict, dict.get()等方法,不要犹豫,各种其他的Python的hash table感觉也没啥用,徒增烦恼。

5. 学习时长

30分钟

383. 赎金信 - 力扣(LeetCode)

1. 文章链接

代码随想录 (programmercarl.com)

2. 看到题目的第一想法

当然是将magazine中所有的字符,按照{字符: 在杂志中的出现次数}统计。

然后遍历ransomNote中每一个字符,出现在hash table中的,且value不是0的,就给对应value-1。如果value是0,那就返回False.

class Solution:
    def canConstruct(self, ransomNote: str, magazine: str) -> bool:
        hash_dict = dict()
        for char in magazine:
            hash_dict[char] = hash_dict.get(char, 0) + 1
        for char in ransomNote:
            times = hash_dict.get(char, 0)
            if times <= 0:
                return False
            else:
                hash_dict[char] = hash_dict.get(char, 0) - 1
        return True

3. 实现过程中遇到的困难

4. 看完代码随想录之后的想法

可以用数组,会更省空间

5. 学习时长

20分钟

15. 三数之和 - 力扣(LeetCode)※(difficult)

1. 文章链接

代码随想录 (programmercarl.com)

2. 看到题目的第一想法

3 <= nums.length <= 3000意味着前两个数字用for循环,应该不太行。

3. 实现过程中遇到的困难

哈希表应该不能做这道题,因为最低要构建第三个数字的set, 前两个数字用O(n2)O(n^2)求和,这个太费时间了。 况且数组中存在值相等元素,set就没办法应对。

4. 看完代码随想录之后的想法

排序。 双指针。 用i遍历数组,i右侧两个指针leftright。 去重,

  1. 因为i前后相邻可能遍历多次相等的元素,所以nums[i]一定要和nums[i-1]进行比较。
  2. left和right也要去重,所以要比较nums[left]==nums[left-1]以及nums[right]==nums[right+1]
class Solution:
    def threeSum(self, nums: List[int]) -> List[List[int]]:
        result = []
        nums.sort()
        for i in range(len(nums) - 2):
            if nums[i] > 0:
                return result
            if (i > 0) and (nums[i] == nums[i - 1]):
                continue
            sum_last_two = 0 - nums[i]
            left = i + 1
            right = len(nums) - 1
            while left < right:
                sum_value = nums[i] + nums[left] + nums[right]
                if sum_value > 0:
                    right -= 1
                if sum_value < 0:
                    left += 1
                if sum_value == 0:
                    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


过程中需要注意的是,如果sum_value==0的情况下,需要两边同时收缩,而不是不动了,不然就会死循环。

5. 学习时长

40分钟

18. 四数之和 - 力扣(LeetCode)

1. 文章链接

代码随想录 (programmercarl.com)

2. 看到题目的第一想法

和三数之和应该使用同样的思路,只不过不是只遍历一个i,而是外侧需要i,j双层循环。

class Solution:
    def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
        result = []
        nums.sort()
        for i in range(len(nums) - 3):
            if (nums[i] >= target) and (target > 0):
                break
            if (i > 0) and (nums[i] == nums[i - 1]):
                continue
            for j in range(i + 1, len(nums) - 2):
                if (target > 0) and (nums[i] + nums[j] >= target):
                    break
                if (j > (i + 1)) and (nums[j] == nums[j - 1]):
                    continue
                left = j + 1
                right = len(nums) - 1
                while left < right:
                    sum_int = nums[i] + nums[j] + nums[left] + nums[right]
                    if sum_int < target:
                        left += 1
                    if sum_int > target:
                        right -= 1
                    if sum_int == target:
                        result.append([nums[i], nums[j], 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
                        right -= 1
                        left += 1
        return result

3. 实现过程中遇到的困难

内层循环如果出现比target大且target为正的情况,不应该立刻就return,这样外层循环也会终止,容易丢失此后的结果。

4. 看完代码随想录之后的想法

思想跟三数之和差不多,就是需要额外注意一些细微的剪枝条件。

5. 学习时长

30分钟。