leetCode--n数之和--哈希表/双指针

n数之和

两数之和

给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那两个整数,并返回他们的数组下标。不能重复利用这个数组中同样的元素。
题目链接:https://leetcode-cn.com/problems/two-sum/

示例:
给定 nums = [2, 7, 11, 15], target = 9
因为 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]

思路:设定一个哈希表map,记录每个值对应的索引i,通过判断target-nums[i]的值是否存在来确定另一个值的位置。

/* 两数之和 */
var twoSum = function (nums, target) {
    let map = {};
    for (let i = 0; i < nums.length; i++) {
        if (map[target - nums[i]] !== undefined) {
            return [map[target - nums[i]], i];
        }
        map[nums[i]] = i;
    }
};
let res = twoSum([2, 7, 11, 15], 9);//[0,1]
console.log(res);

三数之和

给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有满足条件且不重复的三元组。
注意:答案中不可以包含重复的三元组。
题目链接:https://leetcode-cn.com/problems/3sum

示例:
给定数组 nums = [1, 0, -1, 0, -2, 2],和 target = 0。
满足要求的四元组集合为:
[
  [-1,  0, 0, 1],
  [-2, -1, 1, 2],
  [-2,  0, 0, 2]
]

思路1:每次循环确定nums[i],另外两数之和为target-nums[i],利用上面的两数之和方法即可求到对应值,但是提交超时。

/* ---------------哈希表实现(超时)--------------- */
var threeSum = function (nums) {
    let set = new Set();
    for (let i = 0; i < nums.length - 2; i++) {
        /* 去重 */
        if (i > 0 && nums[i] === nums[i - 1]) continue;
        /* 设置map标记 */
        let map = {};
        for (let j = i + 1; j < nums.length; j++) {
            if (!map[nums[j]]) {
                /* 标记第三个值 */
                map[0 - nums[i] - nums[j]] = 1;
            } else {/* 访问到前面标记的值 */
                /* 排序后转换为字符串才能在set去重 */
                set.add([nums[i], 0 - nums[i] - nums[j], nums[j]].sort().toString());
            }
        }
    }
    let res = [];
    /* 将set内的字符串转数组给res */
    set.forEach(v => res.push(v.split(',')));
    /* 子数组排序输出 */
    return res.sort();
};
console.log(threeSum([-1, 0, 1, 2, -1, -4]));//[ [ '-1', '-1', '2' ], [ '-1', '0', '1' ] ]

思路2:先将nums数组排序,然后i遍历,转换为求另外两数之和,求两数之和的方式改成设置两个指针sted,从数组的两端走,根据两处值的和nums[st]+nums[ed]大小确定st走还是ed走,符合条件则将nums[i],nums[st],nums[ed]构成的数组放到res中。

/* ----------------双指针实现---------------- */
var threeSum = function (nums) {
    /* 排序 */
    nums.sort((x, y) => x - y);
    /* 全为正或全为负则退出 */
    if (nums[0] >= 0 || nums[nums.length - 1] <= 0) return [];
    let res = [];
    /* i从左往右 */
    for (let i = 0; i < nums.length - 2; i++) {
        /* 去重 */
        if (i >= 1 && nums[i] === nums[i - 1]) continue;
        /* 另外两个数之和 */
        let target = 0 - nums[i];
        /* 指针头和尾 */
        let st = i + 1, ed = nums.length - 1;
        if (nums[i] > 0) break;
        while (st < ed) {
            let sum = nums[st] + nums[ed];
            if (sum < target) {
                st++;
            } else if (sum > target) {
                ed--;
            } else {
                /* 排序后插入 */
                res.push([nums[i], nums[st], nums[ed]]);
                while (st < ed && nums[st + 1] === nums[st]) st++;
                while (st < ed && nums[ed - 1] === nums[ed]) ed--;
                st++;
                ed--;
            }
        }
    }
    return res;
};
console.log(threeSum([-1, 0, 1, 2, -1, -4]));//[ [ '-1', '-1', '2' ], [ '-1', '0', '1' ] ]

四数之和

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

示例:
给定数组 nums = [1, 0, -1, 0, -2, 2],和 target = 0。
满足要求的四元组集合为:
[
  [-1,  0, 0, 1],
  [-2, -1, 1, 2],
  [-2,  0, 0, 2]
]

思路:与三数之和双指针一样的步骤,多加一层循环,并且给新的循环加去重判断即可。

/* 四数之和 */
var fourSum = function (nums, target) {
    let res = [];
    nums.sort((x, y) => x - y); //排序 [ -3, -2, -1, 0, 0,  1,  2, 3 ]
    /* 遍历第1个数 */
    for (let i = 0; i < nums.length - 3; i++) {
        /* 与i相等的数结果相等,为了去重直接跳过 */
        if (i > 0 && nums[i] === nums[i - 1]) continue;
        /* 第2个数 */
        for (let j = i + 1; j < nums.length - 2; j++) {
            /* 去重 */
            if (j > i + 1 && nums[j] === nums[j - 1]) continue;
            /* 设置双指针选取后两个数 */
            let x = j + 1, y = nums.length - 1;
            /* 剩余值 */
            let tgt = target - nums[i] - nums[j];
            while (x < y) {
                if (nums[x] + nums[y] < tgt) {
                    x++;
                } else if (nums[x] + nums[y] > tgt) {
                    y--;
                } else {
                    /* 符合条件 */
                    res.push([nums[i], nums[j], nums[x], nums[y]]);
                    /* 去重 */
                    while (x < y && nums[x] === nums[x + 1]) x++;
                    while (x < y && nums[y] === nums[y - 1]) y--;
                    /* 移动 */
                    x++; y--;
                }
            }
        }
    }
    return res;
};
let arr = [-3, -2, -1, 0, 0, 1, 2, 3];
let target = 0;
console.log(fourSum(arr, target));
/* 
[
    [-3, -2, 2, 3],
    [-3, -1, 1, 3],
    [-3, 0, 0, 3],
    [-3, 0, 1, 2],
    [-2, -1, 0, 3],
    [-2, -1, 1, 2],
    [-2, 0, 0, 2],
    [-1, 0, 0, 1]
]
 */
posted @ 2020-04-14 23:18  aeipyuan  阅读(180)  评论(0编辑  收藏  举报