代码随想录算法训练营59期day 7第三章 哈希表part02

454.四数相加II

题目:给你四个整数数组 nums1nums2nums3 和 nums4 ,数组长度都是 n ,请你计算有多少个元组 (i, j, k, l) 能满足:

  • 0 <= i, j, k, l < n
  • nums1[i] + nums2[j] + nums3[k] + nums4[l] == 0

题目链接/文章讲解/视频讲解:代码随想录

没啥思路....看视频讲解

整体思路:使用哈希表统计 nums1 + nums2 的频率,然后检查 -(nums3 + nums4) 是否存在

map的赋值取值方式要注意,使用set和get

383. 赎金信

题目:给你两个字符串:ransomNote 和 magazine ,判断 ransomNote 能不能由 magazine 里面的字符构成。

如果可以,返回 true ;否则返回 false 。

magazine 中的每个字符只能在 ransomNote 中使用一次。

题目链接/文章讲解:代码随想录

看了下思路,先记录magazine 字母出现的次数,对应ransomNote字母出现做减法,最终没有小于0的即满足条件

15. 三数之和

题目:给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != ji != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请你返回所有和为 0 且不重复的三元组。

注意:答案中不可以包含重复的三元组。

题目链接/文章讲解/视频讲解:代码随想录

使用哈希法涉及到去重问题,比较麻烦,使用双指针

1. 代码的整体思路

  1. 排序数组

    • nums.sort((a, b) => a - b)

    • 排序后,相同的数字会相邻,方便后续去重,同时可以用 双指针 优化搜索。

  2. 外层循环(固定第一个数 nums[i]

    • 遍历数组,固定 nums[i] 作为三元组的第一个数。

    • 如果 nums[i] > 0,由于数组已排序,后面的数都更大,不可能再找到 nums[i] + nums[j] + nums[k] = 0,直接返回结果。

  3. 内层双指针(寻找 nums[left]nums[right]

    • left = i + 1right = len - 1,从 i 的右侧开始向中间搜索。

    • 计算 sum = nums[i] + nums[left] + nums[right]

      • 如果 sum < 0,说明 nums[left] 太小,left++(向右移动)。

      • 如果 sum > 0,说明 nums[right] 太大,right--(向左移动)。

      • 如果 sum === 0,找到一个有效三元组,加入结果,并跳过重复值。


2. 去重逻辑详解

(1) 外层循环去重:if (iNum == nums[i - 1]) continue

  • 作用:避免 nums[i] 重复使用。

  • 示例

    • 假设 nums = [-1, -1, 0, 1],排序后仍然是 [-1, -1, 0, 1]

    • i = 0nums[i] = -1,正常处理。

    • i = 1nums[i] = -1,但 nums[i] == nums[i - 1](前一个也是 -1),所以 continue,跳过这个 i,避免重复计算 [-1, 0, 1] 两次。

(2) 内层双指针去重:while (left < right && nums[left] == nums[left + 1]) left++

  • 作用:跳过 nums[left] 的重复值。

  • 示例

    • 假设 nums = [-2, 0, 0, 2, 2],当 i = 0nums[i] = -2),left = 1right = 4

    • 第一次找到 [-2, 0, 2] 后:

      • nums[left] = 0nums[left + 1] 也是 0,所以 left++ 跳过重复的 0

      • nums[right] = 2nums[right - 1] 也是 2,所以 right-- 跳过重复的 2

    • 这样避免重复添加 [-2, 0, 2] 多次。

eg:

输入:nums = [-1, 0, 1, 2, -1, -4]

    排序后:[-4, -1, -1, 0, 1, 2]

    外层循环:

        i = 0,nums[i] = -4:

            left = 1,right = 5

            sum = -4 + (-1) + 2 = -3 < 0 → left++

            sum = -4 + (-1) + 2 = -3 < 0 → left++(跳过重复的 -1)

            sum = -4 + 0 + 2 = -2 < 0 → left++

            ...(未找到匹配)

        i = 1,nums[i] = -1:

            left = 2,right = 5

            sum = -1 + (-1) + 2 = 0 → 加入结果 [-1, -1, 2]

            跳过重复的 left 和 right,left++,right--

            sum = -1 + 0 + 1 = 0 → 加入结果 [-1, 0, 1]

        i = 2,nums[i] = -1(与前一个 -1 相同,跳过)

        i = 3,nums[i] = 0:

            left = 4,right = 5

            sum = 0 + 1 + 2 = 3 > 0 → right--

            不满足 left < right,退出循环

    最终结果:[[-1, -1, 2], [-1, 0, 1]]

18. 四数之和

题目:给你一个由 n 个整数组成的数组 nums ,和一个目标值 target 。请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], nums[b], nums[c], nums[d]] (若两个四元组元素一一对应,则认为两个四元组重复):

  • 0 <= a, b, c, d < n
  • abc 和 d 互不相同
  • nums[a] + nums[b] + nums[c] + nums[d] == target

你可以按 任意顺序 返回答案 。

题目链接/文章讲解/视频讲解:代码随想录

类比三数之和,使用双指针

在解答过程中遇到的错误:

(1)排序的写法要注意,按顺序从小到大排序sort((a, b) => a - b)

(2)去重的原则

ijleftright 移动时跳过重复值

(3)j的循环

使用双重 for 循环固定 ij,再用双指针找 leftright

整体思路自己写出了,遇到了以上小的错误点导致结果运行失败

有点强度,多看多思考

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值