(二三四)数之和
两数之和
1. 问题描述
给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
你可以按任意顺序返回答案。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/two-sum。
2. 解题思路
- num1+num2=target,将num2转化为target-num1
- 定义一个空数组arrNum[],以nums[i]的值为下标,以nums[i]的下标为值
- 循环遍历
- 当num2在arrNum[]中不存在,则将nums的数组下标存进arrNum中,若存在,说明找到了符合两数之和的num2,返回结果
var twoSum = function(nums, target) {
var arrNum = {};//存储出现过的数组元素
for(var i = 0; i < nums.length; i++){
var otherNum = target - nums[i];//目标值-当前遍历值得到另一个整数
var otherNumIndex = arrNum[otherNum]//另一个整数的下标
if(otherNumIndex != undefined && otherNumIndex != i){
return arrNum = [otherNumIndex,i];
}
else{
arrNum[nums[i]] = i;
}
}
};
3. 图解
target | 9 | 9 | 9 | 9 | 9 |
---|---|---|---|---|---|
i | 0 | 1 | 2 | 3 | 4 |
num[i] | 2 | 3 | 4 | 8 | 7 |
otherNum=target-num[i] | 7 | 6 | 5 | 1 | 2 |
otherNumIndex | arrNum[7] | arrNum[6] | arrNum[5] | arrNum[1] | arrNum[2] |
otherNumIndex在arrNum中存在否 | x | x | x | x | √ |
j=num[i] | 2 | ||||
arrNum[j] | 0 | ||||
j=num[i] | 3 | ||||
arrNum[j] | 1 | ||||
j=num[i] | 4 | ||||
arrNum[j] | 2 | ||||
j=num[i] | 8 | ||||
arrNum[j] | 3 | ||||
otherNumIndex | 0 | ||||
i | 4 |
两数之和(输入有序数组)
1. 问题描述
给定一个已按照 升序排列 的整数数组 numbers ,请你从数组中找出两个数满足相加之和等于目标数 target 。
函数应该以长度为 2 的整数数组的形式返回这两个数的下标值。numbers 的下标 从 1 开始计数 ,所以答案数组应当满足 1 <= answer[0] < answer[1] <= numbers.length 。
你可以假设每个输入只对应唯一的答案,而且你不可以重复使用相同的元素。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/two-sum-ii-input-array-is-sorted
2.解题思路一
- 定义一个空数组,存储下标值
- 左右指针,循环遍历
- 左指针指向的值+右指针指向的值=target,返回左右指针,根据题意,需要进行+1处理。因为数组下标是从0开始的
- 若和大于目标值,左指针右移
- 若和小于目标值,右指针左移
var twoSum = function(numbers, target) {
var arrNum = [];
var len = numbers.length;
var left = 0;
var right = len - 1;
while(left < right){
if(numbers[left] + numbers[right] == target){
return arrNum = [left + 1, right + 1];
}
else if(numbers[left] + numbers[right] > target) right--;
else if(numbers[left] + numbers[right] < target) left++;
}
return arrNum;
};
3. 图解一
输入:numbers = [2,7,11,15], target = 9
输出:[1,2]
解释:2 与 7 之和等于目标数 9 。因此 index1 = 1, index2 = 2 。
下标 | 0 | 1 | 2 | 3 | |
---|---|---|---|---|---|
nums | 2 | 7 | 11 | 15 | 执行 |
left | right | nums[left]+nums[right]>target,right– | |||
left | right | nums[left]+nums[right]>target,right– | |||
left | right | nums[left]+nums[right]=target,return [left+1,right+1] |
4. 解题思路二
- 使用哈希表记录目标值的下标
- for循环遍历
var twoSum = function(numbers, target) {
let num = new Map();
for(let i = 0; i < numbers.length; i++){
let otherNum = target - numbers[i];
if(num.has(otherNum)) return [num.get(otherNum), i + 1];
num.set(numbers[i], i + 1);
}
};
5. 图解二
输入:numbers = [2,4,7,11,15], target = 9
输出:[1,3]
i | target | numbers[i] | otherNum | num | 执行 | set | return |
---|---|---|---|---|---|---|---|
0 | 9 | 2 | 7 | [] | otherNum在num中不存在,将该值存进num | num=[2,1] | |
1 | 9 | 4 | 5 | [2,1] | otherNum在num中不存在,将该值和遍历值i存进num | num=[[2,1],[4,2]] | |
2 | 9 | 7 | 2 | [[2,1],[4,2]] | otherNum在num中存在,返回该值在num中的下标和当前遍历值i+1 | [1,3] |
三数之和
1. 问题描述
给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。
注意:答案中不可以包含重复的三元组。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/3sum
2.解题思路
- 对数组nums从小到大进行排序
- for循环+双指针
var threeSum = function(nums) {
let arrNum = [];
if(nums == null || nums.length < 3) return arrNum;
nums.sort((a, b) => a - b); // 排序
//以排头为初始值,并取左右两端的值
for(var i = 0; i < nums.length - 2; i++){
var left = i + 1;
var right = nums.length - 1;
if(nums[i] > 0) break; //取到大于0的值,说明三数之和一定大于0
if(i > 0 && nums[i] == nums[i - 1]) continue;//取值重复
while(left < right){
if(nums[i] + nums[left] + nums[right] == 0){
arrNum.push([nums[i], nums[left], nums[right]]);
while(left < right && nums[left] == nums[left + 1]) left++;
while(left < right && nums[right] == nums[right - 1]) right--;
left++;
right--;
}
else if(nums[i] + nums[left] + nums[right] > 0) right--;
else if(nums[i] + nums[left] + nums[right] < 0) left++;
}
}
return arrNum;
};
3.图解
输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]
nums | -1 | 0 | 1 | 2 | -1 | -4 |
---|---|---|---|---|---|---|
排序后 | -4 | -1 | -1 | 0 | 1 | 2 |
轮数 | -4 | -1 | -1 | 0 | 1 | 2 | 执行 |
---|---|---|---|---|---|---|---|
1 | i | left | right | i+left+right<0,left++ | |||
1 | i | left | right | i+left+right<0,left++ | |||
1 | i | left | right | i+left+right<0,left++ | |||
1 | i | left | right | i+left+right<0,left++ | |||
1 | i | left/right | i++ | ||||
2 | i | left | right | i+left+right=0,left++,right–,[-1,-1,2] | |||
2 | i | left | right | i+left+right=0,left++,right–,[-1,0,1] | |||
2 | i | right | left | i++ | |||
3 | i | left | right | num[i]=num[i-1],i++ | |||
4 | i | left | right | i+left+right>0,right– | |||
4 | i | left/right | return arrNum |
最接近的三数之和
1. 问题描述
给定一个包括 n 个整数的数组 nums 和 一个目标值 target。找出 nums 中的三个整数,使得它们的和与 target 最接近。返回这三个数的和。假定每组输入只存在唯一答案。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/3sum-closest
2. 解题思路
- 将数组升序排列
- for循环+双指针
- 类似于三数之和,只是每轮需要判断三数之和与目标值的差值的绝对值是否最小。
var threeSumClosest = function(nums, target) {
var arrNum = [];
if(nums == null || nums.length < 3) return arrNum;
var min = Number.MAX_VALUE;
var result = Number.MAX_VALUE;
nums.sort((a, b) => (a - b));
for(var i = 0; i < nums.length - 2; i++){
var left = i + 1;
var right = nums.length - 1;
while(left < right){
var sum = nums[i] + nums[left] + nums[right];
if(Math.abs(target - sum) < min){
min = Math.abs(target - sum);
result = sum;
}
if(sum == target) return target;//与目标值相同,直接返回
else if(sum > target) right--;
else if(sum < target) left++;
}
}
return result;
};
四数之和
1. 问题描述
给定一个包含 n 个整数的数组 nums 和一个目标值 target,判断 nums 中是否存在四个元素 a,b,c 和 d ,使得 a + b + c + d 的值与 target 相等?找出所有满足条件且不重复的四元组。
注意:答案中不可以包含重复的四元组。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/4sum
2.解题思路
- 对数组进行排序
- 双重for循环 + 双指针
var fourSum = function(nums, target) {
var arrNum = [];
var len = nums.length;
nums.sort((a, b) => a - b);
if(nums == null || len < 4) return arrNum;
for(var i = 0; i < len - 3; i++){
if(nums[i] + nums[i + 1] + nums[i + 2] + nums[i + 3] > target) break;
if(nums[i] + nums[len - 1] + nums[len - 2] + nums[len - 3] < target) continue;
if(i > 0 && nums[i] == nums[i - 1]) continue;
for(var j = i + 1; j < len - 2; j++){
if(j > i + 1 && nums[j] == nums[j - 1]) continue;
if(nums[i] + nums[j] + nums[j + 1] + nums[j + 2] > target) break;
if(nums[i] + nums[j] + nums[len - 1] + nums[len - 2] < target) continue;
var left = j + 1;
var right = len - 1;
while(left < right){
//找到目标四元组
if(nums[i] + nums[j] + nums[left] + nums[right] == target){
arrNum.push([nums[i], nums[j], nums[left], nums[right]]);
while(left < right && nums[left] == nums[left + 1]) left++;
while(left < right && nums[right] == nums[right - 1]) right--;
left++;
right--;
}
//四元组比目标值小,左移
else if(nums[i] + nums[j] + nums[left] + nums[right] < target) left++;
//四元组比目标值大,右移
else if(nums[i] + nums[j] + nums[left] + nums[right] > target) right--;
}
}
}
return arrNum;
};
3.图解
输入:nums = [-1,0,-1,0,-2,2], target = 0
输出:[[-2,0,0,2],[-1,-1,0,2]]
nums | -1 | 0 | -1 | 0 | -2 | 2 |
---|---|---|---|---|---|---|
排序后 | -2 | -1 | -1 | 0 | 0 | 2 |
轮数(ij) | -2 | -1 | -1 | 0 | 0 | 2 | 执行 |
---|---|---|---|---|---|---|---|
11 | i | j | left | right | i+j+left+right<0,left++ | ||
11 | i | j | left | right | i+left+right<0,left++ | ||
11 | i | j | left | right | num[left]==num[left+1],left++ | ||
11 | i | j | left/right | j++ | |||
12 | i | j | left | right | i+j+left+right<0,left++ | ||
12 | i | j | left | right | num[left]==num[left+1],left++ | ||
12 | i | j | left/right | j++ | |||
12 | i | j | left | right | i+j+left+right=0,left++,right–,[-2.0,0,2] | ||
12 | i | j | right | left | i++ | ||
21 | i | j | left | right | i+j+left+right=0,left++,right–,[-1.-1,0,2] | ||
21 | i | j | left/right | j++ | |||
22 | i | j | left | right | i+j+left+right>0,right– | ||
22 | i | j | left/right | i++ | |||
31 | i | j | left | right | num[i]=num[i-1],i++ | ||
31 | i | j | left | right | return arrNum |