zoukankan      html  css  js  c++  java
  • 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]
    ]
     */
    
  • 相关阅读:
    数组快速排序法
    javascript 的基本优化
    wdlinux mysql innodb的安装
    中文逗号替换为英文逗号 ,中英文逗号互换
    wdlinux 编译pdo_mysql
    nodejs 简单对mongodb 操作
    node.js 安装
    开启 mysql 的远程连接功能
    文件下载到本地
    webpack基础+webpack配置文件常用配置项介绍+webpack-dev-server
  • 原文地址:https://www.cnblogs.com/aeipyuan/p/12726195.html
Copyright © 2011-2022 走看看