# 1、两数之和等于Target的下标

``````    //方案一：自定义pair类,排序之后使用双指针 时间复杂度o(nlogn),空间复杂度o(1)
// 并实现comparable接口-compare方法重写（当然也可以使用匿名内部类，继承comparator类，compare方法重写）

public class Solution {

class Pair implements Comparable<Pair>{
public int key;
public int value;

Pair(int key, int value){
this.key = key;
this.value = value;
}

@Override
public int compareTo(Pair o1){
if(o1.value > this.value)
return -1;
else if( o1.value == this.value)
return 0;
else
return 1;
}
}  //end of Pair Class

public int[] twoSum(int[] numbers, int target) {
// write your code here
int[] res = new int[2];
if(numbers == null || numbers.length <= 1)
return res;
Pair[] pairs = new Pair[numbers.length];
for(int i = 0; i < numbers.length; i ++){
Pair pair = new Pair(i,numbers[i]);
pairs[i] = pair;
}
Arrays.sort(pairs);
int left = 0, right = numbers.length - 1;
while(left < right){
if(pairs[left].value + pairs[right].value == target){
res[0] = Math.min(pairs[left].key, pairs[right].key);
res[1] = Math.max(pairs[left].key, pairs[right].key);
left ++;
right --;
}else if(pairs[left].value + pairs[right].value > target){
right --;
}else
left ++;
}
return res;
}
``````
``````     //方法二：使用hashmap，此时不需要排序。时间复杂度o(n),空间复杂度o(n)
//hashmap中存储键为数值，值为对应的数组下标

public int[] twoSum2(int[] numbers, int target){
if(numbers == null || numbers.length <= 1)
return null;
int[] res = new int[2];
HashMap<Integer, Integer> map = new HashMap<>();  //key-numbers[i]  value- i
for(int i = 0; i < numbers.length; i ++){
//首先判断当前元素与前面的元素是否可以组成target
if(map.keySet().contains(target - numbers[i])){
res[1] = i;
res[0] = map.get(target - numbers[i]); //另一个数的下标序号
return res; //只有一组结果，此处直接返回
}
map.put(numbers[i],i); //将当前元素加入到HashMap
}
return res;
}
``````

# 2、三数之和等于0的组合排列

LintCode

``````public class Solution {
/**
* @param numbers: Give an array numbers of n integer
* @return: Find all unique triplets in the array which gives the sum of zero.
*/
public List<List<Integer>> threeSum(int[] numbers) {
// write your code here

//边界判断
if(numbers == null || numbers.length == 0)
return null;

//返回的二维list
List<List<Integer>> res = new ArrayList<>();

//数组排序
Arrays.sort(numbers);

//枚举首位元素a + 双指针遍历
for(int i = 0; i < numbers.length - 2 && numbers[i] <= 0; i ++){

//首位元素去重
while(i >= 1 && i < numbers.length - 2 && numbers[i] == numbers[i - 1])
i ++;
int left = i + 1;
int right = numbers.length - 1;
//left < right 同时约束了指针的范围，避免了 i++ 越界
while(left < right){
if(numbers[i] + numbers[left] + numbers[right] == 0){
List<Integer> tmp =  new ArrayList<>();
//第二位元素去重
while(left + 1 < right && numbers[left] == numbers[left + 1])
left ++;
//第三位元素去重
while(left < right - 1 && numbers[right] == numbers[right - 1])
right --;
//注意！！去重结束之后仍要同时移动left和right指针
//保证指针移动到了第一个不是重复元素的位置上
left ++; right --;
}else if(numbers[i] + numbers[left] + numbers[right] > 0)
right --;
else
left ++;
}
}

return res;
}
}
``````

# 3、三数之和小于Target的组合总数目

(错误思路：“从数学角度来看，三个数和为target，一定至少有1个小于等于target的数。所以可以A数的范围定在<= target的范围进行枚举，剩余两数则在大于A的范围内进行双指针遍历”。 这种想法非常非常错误的，比如`target= (-4) = (-2) + (-2) + 0`，三个数都比target要大。当target为0和正数的时候，刚才的说法才是正确的。）

``````public class Solution {
/**
* @param nums:  an array of n integers
* @param target: a target
* @return: the number of index triplets satisfy the condition nums[i] + nums[j] + nums[k] < target
*/
public int threeSumSmaller(int[] nums, int target) {
// Write your code here
int cnt = 0;
if(nums == null || nums.length == 0)
return cnt;
//数组排序后方可使用双指针
Arrays.sort(nums);

//枚举首位数字
for(int i = 0; i <= nums.length - 3; i ++){
int left = i + 1;
int right = nums.length - 1;
//确定首位数字后，双指针遍历
while(left < right){
//当和小于target时：保持当前left不变，right指针从此处前移到left+1，所有的和都将小于target
//所以此时满足条件的情况的数目等于 right - (left + 1) + 1 = right - left
if(nums[left] + nums[right] < target - nums[i]){
cnt += right - left;
left ++;
}else
right --;
}
}
return cnt;
}
}
``````

# 4、四叔之和等于Target的组合

``````public class Solution {
/**
* @param numbers: Give an array
* @param target: An integer
* @return: Find all unique quadruplets in the array which gives the sum of zero
*/
public List<List<Integer>> fourSum(int[] numbers, int target) {
// write your code here
List<List<Integer>> res = new ArrayList<>();
if(numbers == null || numbers.length == 0)
return res;

Arrays.sort(numbers);
//a元素遍历
for(int i = 0; i < numbers.length - 3; i ++){

//a元素去重
while(i > 0 && i <  numbers.length - 3 && numbers[i] == numbers[i - 1])
i ++;
//b元素遍历
for(int j = i + 1; j < numbers.length - 2; j ++){

//b元素去重
while(j > i + 1 &&  j < numbers.length - 2 && numbers[j] == numbers[j - 1])
j ++;

//双指针
int left = j + 1;
int right  = numbers.length - 1;
while(left < right){
if(numbers[left] + numbers[right] + numbers[i] + numbers[j] == target){
List<Integer> tmp = new ArrayList<>();
//第三个元素去重
while(left + 1 < right && numbers[left + 1] == numbers[left])
left ++;
//第四个元素去重
while(left < right - 1 && numbers[right] == numbers[right - 1])
right --;
left ++; right --;
}else if(numbers[left] + numbers[right] + numbers[i] + numbers[j] < target)
left ++;
else
right --;
}
}
}
return res;
}
}
``````

# 5、K数之和

List = [1,2,3,4] ； k = 2 ； target = 5

``````public class Solution {
/**
* @param A: An integer array
* @param k: A positive integer (k <= length(A))
* @param target: An integer
* @return: An integer
*/
public int kSum(int[] A, int k, int target) {
// write your code here
if(A == null || A.length ==0 || k <= 0)
return 0;
//正整数的总数从0 - A.length； 可选的个数从 0 - k; target也是从 0 - target
int[][][] f = new int[A.length + 1][ k + 1][target + 1];
//初始值
for(int i = 0; i <= A.length; i ++){
f[i][0][0] = 1;
}
//f[i][j][t] = f[i - 1][j][t] + f[i - 1][j - 1][t -A[i]]
for(int i = 1; i <= A.length; i ++)
for(int j = 1; j <= k; j ++)
for(int t = 1; t <= target; t ++){
f[i][j][t] = f[i - 1][j][t];
f[i][j][t] += t - A[i - 1] >=0 ? f[i - 1][j - 1][t -A[i - 1]] : 0;
}
return f[A.length][k][target];
}
}
``````
原文作者：LoongTech
原文地址: https://blog.csdn.net/loongkingwhat/article/details/100164890
本文转自网络文章，转载此文章仅为分享知识，如有侵权，请联系博主进行删除。