这种计算几个数据之和的题目,
一般分为
- 在同一个数组中计算几个数之和等于某一个值。
- 还有一种是给几个数组,每个数组中取一个数据,让你算几个数之和等于某一个值。
一般情况下,第二中的难度会更大,因为去重会比较麻烦。
如:
1. 两数之和
给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
你可以按任意顺序返回答案。
题解:
- 这个比较简单,用set集合就可以了,每次都判断集合中是否有数据可以满足当前数据+它等于target。
454. 四数相加 II
给定四个包含整数的数组列表 A , B , C , D ,计算有多少个元组 (i, j, k, l) ,使得 A[i] + B[j] + C[k] + D[l] = 0。
为了使问题简单化,所有的 A, B, C, D 具有相同的长度 N,且 0 ≤ N ≤ 500 。所有整数的范围在 -228 到 228 - 1 之间,最终结果不会超过 231 - 1 。
题解:
- 这道题算是比较简单的,可以使用HashMap来进行求解。
- 首先求数组A,B的和,把所有可能的值都存在HashMap里面,key存值,value存出现的次数。
- 在第二次求数组C和D的和的时候,直接把拿和去存A,B的和的HashMap里面求是否存在值,存在就让count加上该值出现的次数,也就是对应的value。(因为只要下标不一样,就不算重复)
- 最后遍历完输出count就行了。
代码:
class Solution {
public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
int length=nums1.length;
HashMap<Integer,Integer> map1=new HashMap<>();
Integer temp=0;
int count=0;
for(int i=0;i<length;i++){
for(int j=0;j<length;j++){
temp=nums1[i]+nums2[j];
if(map1.containsKey(temp)){
int num=map1.get(temp);
map1.replace(temp,num+1);
}else{
map1.put(temp,1);
}
}
}
for(int i=0;i<length;i++){
for(int j=0;j<length;j++){
temp=nums3[i]+nums4[j];
if(map1.containsKey(-temp)){
int num=map1.get(-temp);
count=count+num;
}
}
}
return count;
}
}
15. 三数之和
给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。
注意:答案中不可以包含重复的三元组。
题解:
解法一
- 也可以使用HashMap,先两层for循环,这样就确定了a,b。然后再在HashMap里面判断是否存在0-(a+b)就行。
- 然后把符合条件的情况存起来,再做去重,不过这样去重的操作比较复杂,不推荐。
解法二
- 可以使用双指针,
- 先排序
- 一层循环,把其中一个值确定下来。
- 然后里面一个while循环,然后双指针一个left指向确定值的下一个值,一个right指向最后一个。
- 然后根据三者的和与target的结果对比,移动指针,当left>=right的时候退出循环。
- 还有一步就是需要去重,首先给i去重。可以通过检测相邻的数据是否一样来进行去重。
- 但是不能一开始就去重,这样可能会导致把类似于(-1)+(-1)+2=0的情况忽略。因此需要先用当前值运行一次,然后再去重。
- 也就是每次进行去重操作之前都用短路与,前面条件是i>0,这样确保i第一次取值的情况不会被忽略。
- 最后两个指针的去重,只需要在每次找到符合条件的元组的时候进行就可以了,其他数据不会进入结果集,因此不需要去重也没事。
代码:
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> lists=new ArrayList<List<Integer>>();
if(nums.length<3){
return lists;
}
Arrays.sort(nums);
for(int i=0;i<nums.length;i++){
if(nums[i]>0){
break;
}
if(i>0 && nums[i]==nums[i-1]){//i去重
continue;
}
int j=i+1;
int k=nums.length-1;
while(j<k){
int temp=nums[i]+nums[j]+nums[k];
if(temp==0){
List<Integer> list=new ArrayList<Integer>();
list.add(nums[i]);
list.add(nums[j]);
list.add(nums[k]);
lists.add(list);//后面两个指针的去重只有在找到一个符合的三元组之后
//才需要把可能一样是这个三元组的重复部分去掉
while(k>j&&nums[k]==nums[k-1]){
k--;
}
while(j<k&&nums[j]==nums[j+1]){
j++;
}
k--;
j++;
}else if(temp>0){
k--;
}else{
j++;
}
}
}
return lists;
}
}
18. 四数之和
给定一个包含 n 个整数的数组 nums 和一个目标值 target,判断 nums 中是否存在四个元素 a,b,c 和 d ,使得 a + b + c + d 的值与 target 相等?找出所有满足条件且不重复的四元组。
注意:答案中不可以包含重复的四元组。
题解:
- 该题和上一题的思路差不多,先固定两位,剩下两位使用双指针,去重套路也差不多。
不啰嗦了,直接放代码:
class Solution {
public List<List<Integer>> fourSum(int[] nums, int target) {
List<List<Integer>> lists=new ArrayList<List<Integer>>();
Arrays.sort(nums);
for(int i=0;i<nums.length;i++){
if(nums[i]>0&&nums[i]>target){
return lists;
}
if(i>0&&nums[i]==nums[i-1]){//i去重
continue;
}
for(int j=i+1;j<nums.length;j++){
int k=j+1;
if(j>i+1&&nums[j]==nums[j-1]){//j去重,防止把一开始的第一次数据都去了,所以
//需要等j进入了第一次循环之后才开始去重。
continue;
}
int l=nums.length-1;
while(k<l){
int temp=nums[i]+nums[j]+nums[k]+nums[l];
if(temp==target){
List<Integer> list=new ArrayList<>();
list.add(nums[i]);
list.add(nums[j]);
list.add(nums[k]);
list.add(nums[l]);
while(k<l&&nums[k]==nums[k+1])k++;//k,l去重
while(k<l&&nums[l]==nums[l-1])l--;
k++;
l--;
lists.add(list);
}else if(temp>target){
l--;
}else{
k++;
}
}
}
}
return lists;
}
}