• 算法-求和(两数/三数/四数之和)问题


    1、两数之和​​​​​​​

    解题思路:

    1、淳朴解法:双层遍历,O(n^2) 的复杂度,这个复杂度非常容易导致你的算法超时,不推荐。

    2、空间换时间,Map 来帮忙

     大家记住一个结论:几乎所有的求和问题,都可以转化为求差问题。 

    1. var twoSum = function(nums, target) {
    2. let obj = {} //创建一个对象来存储出现过的数字-对应的索引
    3. for (let i = 0; i < nums.length; i++) {
    4. const curNum = nums[i]; //当前元素
    5. const targetNum = target - curNum //几乎所有的求和问题,都可以转化为求差问题
    6. const targetNumIndex = obj[targetNum]//找到在obj中的索引
    7. if (targetNumIndex !== undefined) {
    8. return [targetNumIndex, i] //如果存在, 直接返回[目标元素的索引, 当前索引]
    9. } else {
    10. obj[curNum] = i //如果不存在,存入当前的元素和对应的索引
    11. }
    12. }
    13. };
    1. var twoSum = function(nums, target) {
    2. const map = new Map();
    3. for (let i = 0; i < nums.length; i++) {
    4. const curNum = nums[i];
    5. const targetNum = target - curNum;
    6. const targetNumIndex = map.get(targetNum);
    7. if (targetNumIndex !== undefined) {
    8. return [targetNumIndex, i];
    9. } else {
    10. map.set(curNum, i);
    11. }
    12. }
    13. };

    2、三数之和

    解题思路:

    外层循环遍历指针ℹ️

    内层用双指针寻找满足条件的元素

    先排序,可以方便去重

    1. var threeSum = function (nums) {
    2. nums.sort((a, b) => a - b) //排序
    3. const result = []
    4. for (let i = 0; i < nums.length-2; i++) { //外层遍历,内层双指针
    5. const n1 = nums[i];
    6. if (n1 > 0) break // n1比0大,就不用做了
    7. if (i - 1 >= 0 && nums[i - 1] == n1) continue //重复的数也跳过
    8. let left = i + 1 //左指针
    9. let right = nums.length - 1 //右指针
    10. while (left < right) {
    11. let n2 = nums[left],n3 = nums[right];
    12. if (n1 + n2 + n3 === 0) {
    13. result.push([n1, n2, n3])
    14. while (left < right && nums[left] === n2) left++ // 去重,直到指向不一样的数
    15. while (left < right && nums[right] === n3) right-- //去重, 直到指向不一样的数
    16. } else if (n1 + n2 + n3 < 0) { //小于0,那么左指针往右移
    17. left++
    18. } else { //大于0,那么右指针左移
    19. right--
    20. }
    21. }
    22. }
    23. return result
    24. };

    3、四数之和​​​​​​​

    解题思路:排序+双指针

    参考三数之和,相比多了一层循环

    注意事项:

    !!!!:一定注意代码中是 先进行了指针的移动 还是 先进行了去重的比较, 对于不同的顺序, 比较的元素是完全不同的。

    若先进行了指针的移动, 对于左指针来说, 需要比较的元素就是 当前元素和前面的一个元素

    对于 i 和 j 由于每次循环完都先 i++、j++ 了,所以是 先进行了指针的移动再判断重复,所以是 nums[i] === nums[i - 1]


    若先进行去重的比较, 那比较的元素就是 当前元素和后面的一个元素, 再进行指针的移动. 对于右指针的情况正好是完全相反的.

    while (left < right && nums[left + 1] === nums[left]) left++ // 去重

    while (left < right && nums[right - 1] === nums[right]) right-- // 去重

    对于 left 和 right ,是 先进行了判断重复再进行指针的移动,所以是两个 while 循环后才 left++, right--

    1. var fourSum = function (nums, target) {
    2. const len = nums.length
    3. if (len < 4) return []
    4. nums.sort((a, b) => a - b) //排序
    5. const result = []
    6. for (let i = 0; i < len - 3; i++) {
    7. if (i > 0 && nums[i] === nums[i - 1]) continue // 去重
    8. for (let j = i + 1; j < len - 2; j++) {
    9. if (j > i + 1 && nums[j] === nums[j - 1]) continue // 去重
    10. let left = j + 1
    11. let right = len - 1
    12. while (left < right) {
    13. if (nums[i] + nums[j] + nums[left] + nums[right] === target) {
    14. result.push([nums[i], nums[j], nums[left], nums[right]])
    15. while (left < right && nums[left + 1] === nums[left]) left++ // 去重
    16. while (left < right && nums[right - 1] === nums[right]) right-- // 去重
    17. // 找到一个符合条件的了,然后两指针同时收缩
    18. right--
    19. left++
    20. } else if (nums[i] + nums[j] + nums[left] + nums[right] > target) {
    21. right--
    22. } else {
    23. left++
    24. }
    25. }
    26. }
    27. }
    28. return result
    29. };

  • 相关阅读:
    用于光波导系统的均匀性探测器
    论文精读:detr:End-to-End Object Detection with Transformers
    年近三十,真的卷不动了
    含文档+PPT+源码等]精品基于Nodejs实现的家政服务微信小程序[包运行成功]Nodejs毕业设计计算机项目源码
    pyquery 的使用
    mmdetection代码教学
    从零开始打造一款基于SpringBoot+SpringCloud的后台权限管理系统
    数据仓库概念
    multi-gneration lru系列 - 怎么决定回收anon还是file
    塔望食研院|骆驼奶市场规模庞大,百亿体量,品牌升级!
  • 原文地址:https://blog.csdn.net/qq_42181069/article/details/125535938