两数之和
题目描述
给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
你可以按任意顺序返回答案。
示例 1:
输入:nums = [2,7,11,15], target = 9 输出:[0,1] 解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。 示例 2:
输入:nums = [3,2,4], target = 6 输出:[1,2] 示例 3:
输入:nums = [3,3], target = 6 输出:[0,1]
提示:
2 <= nums.length <= 104 -109 <= nums[i] <= 109 -109 <= target <= 109 只会存在一个有效答案 进阶:你可以想出一个时间复杂度小于 O(n2) 的算法吗?
解题思路
哈希映射hasMap
- 我们创建一个哈希表;
- 对于每一个 x,我们首先查询哈希表中是否存在 target - x;
- 然后将 x 插入到哈希表中,即可保证不会让 x 和自己匹配。
时空复杂度
-
时间复杂度:O(N),其中 N 是数组中的元素数量。对于每一个元素 x,我们可以 O(1) 地寻找 target - x。
-
空间复杂度:O(N),其中 N 是数组中的元素数量。主要为哈希表的开销。
代码
/**
* @param {number[]} nums
* @param {number} target
* @return {number[]}
*/
var twoSum = function(nums, target) {
let map=new Map();
//
for(let i=0;i<nums.length;i++){
if(!map.has(target-nums[i])){
map.set(nums[i],i);
}else{
return [i,map.get(target-nums[i])]
}
}
};
两数之和变种
题目描述
nums中有多对儿元素之和等于target,请你使用算法返回所有的和为target的元素对儿,其中不能重复;
var twoSum = function(nums, target)
比如nums=[1,2,2,3,3,2,1],target=4;返回的结果即为[[1,3],[2,2]]
解题思路
- 排序+双指针实现;
- 通过排序便于我们进行元素去重;
- 通过left,right双指针相向移动
- 通过while循环进行左右指针指向的相同元素去重;
时空复杂度
- 时间复杂度O(N);while循环O(N),N为nums.length;排序时间复杂度为O(NlogN)
/**
* @param {number[]} nums
* @param {number} target
* @return {number[]}
*/
var twoSum = function(nums, target) {
// 排序+双指针
// 排序
nums.sort((a,b)=>{return a-b})
//双指针left right;
let left=0;right=nums.length-1;
let res=[];
while(left<right){
sum=nums[left]+nums[right]
let leftVal=nums[left],rightVal=nums[right];
if(sum<target){
// 左侧去重
while(left<right&&nums[left]==leftVal) left++;
}else if(sum>target){
// 右侧去重
while(left<right&&nums[right]==rightVal) right--;
}else{
// 去重
res.push([nums[left],nums[right]])
while(left<right&&nums[left]==leftVal)left ++
while(left<right&&nums[right]==rightVal) right--
}
}// end of while
return res;
};
三数之和
给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。
注意:答案中不可以包含重复的三元组。
示例 1:
输入:nums = [-1,0,1,2,-1,-4] 输出:[[-1,-1,2],[-1,0,1]] 示例 2:
输入:nums = [] 输出:[] 示例 3:
输入:nums = [0] 输出:[]
提示:
0 <= nums.length <= 3000 -105 <= nums[i] <= 105
来源:力扣(LeetCode) 链接:leetcode-cn.com/problems/3s… 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
解题思路
- 排序+双指针实现 同上
- 通过排序便于我们进行元素去重;
- 通过left,right双指针相向移动
- 通过while循环进行左右指针指向的相同元素去重;
- 关键点是需要基准值去重
// 基准值去重; if(i>0&&nums[i]===nums[i-1]){ continue }
代码
/**
* @param {number[]} nums
* @return {number[][]}
*/
var threeSum = function(nums) {
// 思路 排序+双指针实现;
let res=[];
// 1、排序
nums.sort((a,b)=>{return a-b});
// 遍历每一个元素作为基准点;
for(let i=0;i<nums.length;i++){
// 对于本题来说 三数之和为0;最小值大于0;一定不存在;
if(nums[i]>0){
return res;
}
//定义左右指针 left right;
let left =i+1,right=nums.length-1;
// 基准值去重;
if(i>0&&nums[i]===nums[i-1]){
continue
}
while(left<right){
let sum=nums[i]+nums[left]+nums[right]
if(sum===0){
// left 去重
while(left<right&&nums[left]===nums[left+1])left ++;
// right 去重
while(left<right&&nums[right]===nums[right-1]) right --;
res.push([nums[i],nums[left],nums[right]]);
left++
right--
}else if(sum<0){
left++
}else {
right--
}
}// end of while
}// end of for
return res;
};
解题思路2
- 确定基准值以后,剩下的数字就是求两数之和 target-nums[i];利用求两数之和twoSum函数;求三数之和
代码
/**
* @param {number[]} nums
* @return {number[][]}
*/
var threeSum = function(nums) {
// 另一种思路; 确定基准值以后,剩下的数字就是求两数之和 target-nums[i];利用求两数之和twoSum函数;
return threeSumTarget(nums,0)
};
var threeSumTarget=function (nums,target){
let res=[];
nums.sort((a,b)=>{return a-b});
// 遍历每个基准点;
for(let i=0;i<nums.length;i++){
// 求两数之和
let tuples=twoSumTarget(nums,i+1,target-nums[i])
//满足tuples 则加入nums[i],并push进res;
console.log(tuples);
for(let j=0;j<tuples.length;j++){
tuples[j].push(nums[i])
res.push(tuples[j]);
}//
while(i<nums.length-1&&nums[i]===nums[i+1]){
i++
}
}// end of for
return res;
}
var twoSumTarget=function(nums,start,target){
let res=[];
let left =start,right=nums.length-1;
while(left<right){
let sum=nums[left]+nums[right]
let leftVal=nums[left],rightVal=nums[right]
if(sum<target){
// left 去重;
while(left<right&&nums[left]===leftVal) left++
}else if(sum>target ){
while(left<right&&nums[right]===rightVal) right--;
}else {
res.push([nums[left],nums[right]]);
// left right 去重;
while(left<right&&nums[left]===leftVal) left++
while(left<right&&nums[right]===rightVal) right--;
}
}// end of while
return res;
}
四数之和
题目描述
给你一个由 n 个整数组成的数组 nums ,和一个目标值 target 。请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], nums[b], nums[c], nums[d]] :
0 <= a, b, c, d < n a、b、c 和 d 互不相同 nums[a] + nums[b] + nums[c] + nums[d] == target 你可以按 任意顺序 返回答案 。
示例 1:
输入:nums = [1,0,-1,0,-2,2], target = 0 输出:[[-2,-1,1,2],[-2,0,0,2],[-1,0,0,1]] 示例 2:
输入:nums = [2,2,2,2,2], target = 8 输出:[[2,2,2,2]]
提示:
1 <= nums.length <= 200 -109 <= nums[i] <= 109 -109 <= target <= 109
来源:力扣(LeetCode) 链接:leetcode-cn.com/problems/4s… 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
解题思路
如果我们求n数之和怎么办呢?
- 由我们之前做过的2数之和,3数之和进而递归演化为nSum:n数之和;
- nSumTarget:n数之和求解公式
- nSumTarget中参数nums,必须是已经排序数组;
- 当n===2时,走两数之和twoSumTarget的双指针方法;
- 当n>2时,穷举第一个数(注意去重);
- 然后递归调用(n-1)Sum,组装答案;
代码
/**
* @param {number[]} nums
* @param {number} target
* @return {number[][]}
*/
var fourSum = function(nums, target) {
nums.sort((a,b)=>{return a-b});
// nsum
return nSumTarget(nums,4,0,target);
};
/**
* * @param {number[]} nums sorted nums
* * @param {number[]} n n数之和
* * @param {number} start 下标左指针
* @param {number} target 求和目标
* @return {number[][]}
*/
var nSumTarget=function(nums,n,start,target){
let size=nums.length;
let res=[]
if(n<2||size<n){
return res;
}
// n===2;两数之和
if(n===2){
// 两数之和
let left =start,right=nums.length-1;
while(left<right){
let sum=nums[left]+nums[right]
let leftVal=nums[left],rightVal=nums[right]
if(sum<target){
// left 去重;
while(left<right&&nums[left]===leftVal) left++
}else if(sum>target ){
while(left<right&&nums[right]===rightVal) right--;
}else {
res.push([nums[left],nums[right]]);
// left right 去重;
while(left<right&&nums[left]===leftVal) left++
while(left<right&&nums[right]===rightVal) right--;
}
}// end of while
}else{
//n>2时,递归计算(n-1)Sum;
for(let i=start;i<size;i++){
// 基准点去重
if(i>start&&nums[i]===nums[i-1]){
continue
}
sub=nSumTarget(nums,n-1,i+1,target-nums[i])
console.log(sub);
for(item of sub){
item.push(nums[i]);
res.push(item);
}
}// end of for
}
return res;
}