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]
]
 */
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章