two sum

入门题

001 两数之和 给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 的那 两个 整数,并返回它们的数组下标。 你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。

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

链接:https://leetcode-cn.com/problems/two-sum

暴力循环法

  1. /**
  2. * @param {number[]} nums
  3. * @param {number} target
  4. * @return {number[]}
  5. */
  6. var twoSum = function(nums, target) {
  7. for(var i = 0 ; i < nums.length ; i++){
  8. for(var j = i + 1 ; j < nums.length ; j++){
  9. if(nums[j] === target-nums[i])
  10. return [i,j];
  11. }
  12. }
  13. return [-1,-1]
  14. };

哈希表法

  1. /**
  2. * @param {number[]} nums
  3. * @param {number} target
  4. * @return {number[]}
  5. */
  6. var twoSum = function(nums, target) {
  7. var map = new Map();
  8. //存入哈希表
  9. for(var i = 0; i <nums.length ; i++){
  10. map.set(nums[i],i)
  11. }
  12. for(var i = 0 ; i < nums.length ; i++){
  13. const other = target - nums[i];
  14. //下标要不同
  15. if(map.has(other) && map.get(other) !== i ){
  16. return [i,map.get(other)];
  17. }
  18. }
  19. return [-1,-1];
  20. };

优化一下,查询哈希表是否存在 target - x,否则将 x 插入到哈希表中,即可保证不会让 x 和自己匹配

  1. var twoSum = function(nums, target) {
  2. var map = new Map();
  3. for(var i = 0 ; i < nums.length ; i++){
  4. if(map.has(target - nums[i])){
  5. return [map.get(target - nums[i]), i];
  6. }else{
  7. map.set(nums[i], i);
  8. }
  9. }
  10. return [-1,-1];
  11. };

两数之和II

给定一个已按照 升序排列 的整数数组 numbers ,请你从数组中找出两个数满足相加之和等于目标数 target 。 函数应该以长度为 2 的整数数组的形式返回这两个数的下标值。numbers 的下标 从 1 开始计数 ,所以答案数组应当满足 1 <= answer[0] < answer[1] <= numbers.length 。

你可以假设每个输入只对应唯一的答案,而且你不可以重复使用相同的元素。

链接:https://leetcode-cn.com/problems/two-sum-ii-input-array-is-sorted

双指针法

  1. var twoSum = function (nums, target) {
  2. var l = 0;
  3. var r = nums.length - 1;
  4. while (l < r) {
  5. var sum = nums[l] + nums[r];
  6. if (sum === target) {
  7. //下标从1开始计数
  8. return [l + 1, r + 1];
  9. } else if (sum < target) {
  10. l++;
  11. } else if (sum > target) {
  12. r--;
  13. }
  14. }
  15. return [-1, -1];
  16. };

引申

  • 假如001题要求返回而不是下标,可以使用先排序后使用双指针法求解,
    1. var twoSum = function (nums, target) {
    2. //排序,注意js排序是按编码,数字排序必需传函数
    3. nums.sort(function (a, b) {
    4. return a - b;
    5. });
    6. var l = 0;
    7. var r = nums.length - 1;
    8. while (l < r) {
    9. var sum = nums[l] + nums[r];
    10. if (sum === target) {
    11. //返回值
    12. return [nums[l], nums[r]];
    13. } else if (sum < target) {
    14. l++;
    15. } else if (sum > target) {
    16. r--;
    17. }
    18. }
    19. return [-1, -1];
    20. };

如果数组里满足和的值不唯一,应该怎么做?

  1. var twoSum = function (nums, target) {
  2. var res = [];
  3. nums.sort(function (a, b) {
  4. return a - b;
  5. });
  6. var l = 0;
  7. var r = nums.length - 1;
  8. while (l < r) {
  9. var sum = nums[l] + nums[r];
  10. if (sum === target) {
  11. res.push([nums[l], nums[r]]);
  12. l++;
  13. r--;
  14. } else if (sum < target) {
  15. l++;
  16. } else if (sum > target) {
  17. r--;
  18. }
  19. }
  20. return res;
  21. };

但是这样,会出现重复:

  1. console.log(twoSum([1,3,1,2,2,3], 4));
  2. //[ [ 1, 3 ], [ 1, 3 ], [ 2, 2 ] ]

如何去重?
数组里重复的直接跳过下标

  1. var twoSum = function (nums, target) {
  2. var res = [];
  3. nums.sort(function (a, b) {
  4. return a - b;
  5. });
  6. var l = 0;
  7. var r = nums.length - 1;
  8. while (l < r) {
  9. var sum = nums[l] + nums[r];
  10. var left = nums[l],
  11. right = nums[r];
  12. if (sum === target) {
  13. res.push([nums[l], nums[r]]);
  14. while (l < r && nums[l] == left) l++;
  15. while (l < r && nums[r] == right) r--;
  16. } else if (sum < target) {
  17. while (l < r && nums[l] == left) l++;
  18. } else if (sum > target) {
  19. while (l < r && nums[r] == right) r--;
  20. }
  21. }
  22. return res;
  23. };

如何优化上述代码?
暂无

three sum

给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。 注意:答案中不可以包含重复的三元组。

来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/3sum

穷举第1个数字,然后调用2Sum函数计算剩下2个数,最后组合出和为target的3元组。

  1. /**
  2. * @param {number[]} nums
  3. * @return {number[][]}
  4. */
  5. //通用二元sum函数
  6. var twoSum = function (nums, start, target) {
  7. var res = [];
  8. var l = start;
  9. var r = nums.length - 1;
  10. while (l < r) {
  11. var sum = nums[l] + nums[r];
  12. var left = nums[l],
  13. right = nums[r];
  14. if (sum === target) {
  15. res.push([nums[l], nums[r]]);
  16. while (l < r && nums[l] == left) l++;
  17. while (l < r && nums[r] == right) r--;
  18. } else if (sum < target) {
  19. while (l < r && nums[l] == left) l++;
  20. } else if (sum > target) {
  21. while (l < r && nums[r] == right) r--;
  22. }
  23. }
  24. return res;
  25. };
  26. var threeSum = function (nums) {
  27. var res = [];
  28. nums.sort(function (a, b) {
  29. return a - b;
  30. });
  31. for (var i = 0; i < nums.length; i++) {
  32. //调用twoSum函数
  33. var res2 = twoSum(nums, i + 1, 0 - nums[i]);
  34. res2.forEach(r => {
  35. r.unshift(nums[i]);//头部插入
  36. res.push(r);
  37. })
  38. //用来保证第一个数字不重复
  39. while (i < nums.length - 1 && nums[i] == nums[i + 1]) i++;
  40. }
  41. return res;
  42. };

如果是4 sum,那么可以再写一层,那么可以抽离出来,写出一个N sum 求解的方法:

//通用nsum函数
var nSum = function (nums, n, start, target) {
    var res = [];
    if (n < 2 ) return res;
    if (n == 2) {
        var l = start;
        var r = nums.length - 1;
        while (l < r) {
            var sum = nums[l] + nums[r];
            var left = nums[l],
                right = nums[r];
            if (sum === target) {
                res.push([nums[l], nums[r]]);
                while (l < r && nums[l] == left) l++;
                while (l < r && nums[r] == right) r--;
            } else if (sum < target) {
                while (l < r && nums[l] == left) l++;
            } else if (sum > target) {
                while (l < r && nums[r] == right) r--;
            }
        }
    } else {
        for (var i = start; i < nums.length; i++) {
            var res2 = nSum(nums, n - 1, i + 1, target - nums[i]);
            res2.forEach(r => {
                r.unshift(nums[i]);
                res.push(r);
            })
            while (i < nums.length - 1 && nums[i] == nums[i + 1]) i++;
        }
    }
    return res;
};

four sum

给定一个包含 n 个整数的数组 nums 和一个目标值 target,判断 nums 中是否存在四个元素 a,b,c 和 d ,使得 a + b + c + d 的值与 target 相等?找出所有满足条件且不重复的四元组。 注意:答案中不可以包含重复的四元组。

来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/4sum

 var fourSum = function (nums, target) {
    nums.sort(function (a, b) {
        return a - b;
    });
    return nSum(nums, 4, 0, target)
};

搞定!