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
遍歷,轉換爲求另外兩數之和,求兩數之和的方式改成設置兩個指針st
,ed
,從數組的兩端走,根據兩處值的和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]
]
*/