2Sum
题意:
给你一组个数组,array[] = {7,11,13,15,1,2,13,4,4}, target = 15,在array中找出两个数之和等于target。输出所有二元组(不能重复,[2, 13]和[13, 2]只能算一组),比如,本题的答案:[2,13],[1,14]。
解体思路:
首先把数组进行排序,然后用behind指针指向排序后数组的头部,用ahead指针指向排序后的数组尾部。如果array[behind] + array[ahead] > target,说明两个数大了,则需要将ahead向前移动一位,那么两数之和就会减小向target靠近。如果array[behind] + array[ahead] < target,说明两个数小了,则需要把behind往后移动一位,那么两数之和就会减小向target靠近。
import java.util.*;
public class _2Sum {
public static List<List<Integer>> _2Sum(int[] array, int target, List<List<Integer>> res) {
boolean flag = false;
int ahead = array.length - 1;
int behind = 0;
while(ahead > behind) {
if(array[ahead] + array[behind] == target) {
flag = true;
res.add(Arrays.asList(array[ahead], array[behind]));
//由于题目要求,不能有重复的元组,那么当ahead和behind指向的数字之和等于target时,需要把ahead之前并且等于array[ahead]的数跳过。
while(ahead > behind) {
if(array[ahead] == array[ahead - 1]) {
ahead--;
}else break;
}
//由于题目要求,不能有重复的元组,那么当ahead和behind指向的数字之和等于target时,需要把behind之后并且等于array[hehind]的数跳过。
while(ahead > behind) {
if(array[behind] == array[behind + 1]){
behind++;
}else break;
}
//去掉重复元素之后,由于array[ahead-1] < array[ahead],array[behind] < array[behind + 1],那么需要同时ahead--和behind++,才可能找到下一个元组。
ahead--;
behind++;
}else if(array[ahead] + array[behind] > target){
//明两个数大了,则需要将ahead向前移动一位,那么两数之和就会减小向target靠近。
ahead--;
}else {
//说明两个数小了,则需要把behind往后移动一位,那么两数之和就会减小向target靠近。
behind++;
}
}
return res;
}
public static void main(String[] args) {
int[] array = new int[]{7,11,13,15,1,2,13,4,4};
List<List<Integer>> res = new LinkedList<>();
//给数组排序
Arrays.sort(array);
int target = 15;
_2Sum(array, target, res);
System.out.println(res);
}
}
3Sum(LeetCode - 15)
题意:
给你一组个数组,array[] = [-1, 0, 1, 2, -1, -4], target = 0,在array中找出3个数之和等于target。输出所有三元组(不能重复,[1, 0, -1]和[-1, 0, 1]算作一个),比如,本题的答案:[2,13],[1, 14]。
题目链接:https://leetcode.com/problems/3sum/description/
解体思路:
首先给数组排序,遍历数组中的每个可能作为三元组中首元素的nums[I],令sum = target - nums[I]。然后在nums[I+1,…,len-1]中寻找nums[ahead] + nums[behind] = sum的二元组。
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
public class _3Sum {
public static List<List<Integer>> _3Sum(int[] nums, int target) {
Arrays.sort(nums);
List<List<Integer>> res = new LinkedList<>();
int len = nums.length;
for(int i = 0; i < len - 2; i++) {
if(i == 0 || (i > 0 && nums[i] != nums[i-1])) { //寻找可能作为三元组首元素的nums[i]。
//后面的元素与前面相同则跳过,因为,nums[i-1] 已经和nums[i...len-1]组合过了(其中还包括nums[i-1]与nums[i]的组合),所以直接跳过array[i]对匹配结果无影响,因为再次使用nums[i]去寻找结果,结果只能是无解(不能使用和其值相等的nums[i-1]了,可能找不到结果)或者找到重复结果。
// 转化为2Sum问题,即在behind和ahead之间寻找等于Sum的问题了。
int behind = i + 1, ahead = len - 1, sum = target - nums[i];
while(behind < ahead) {// 2Sum(参考上面)
if(nums[behind] + nums[ahead] == sum) {
res.add(Arrays.asList(nums[i], nums[behind], nums[ahead]));
while(ahead > behind && nums[ahead] == nums[ahead - 1]) {
ahead--;
}
while(ahead > behind && nums[behind] == nums[behind + 1]) {
behind++;
}
ahead--;
behind++;
}else if(nums[behind] + nums[ahead] > sum) {
ahead--;
}else {
behind++;
}
}
}
}
return res;
}
public static void main(String[] args) {
int[] array = new int[]{-1, 0, 1, 2, -1, -4};
List<List<Integer>> res = new LinkedList<>();
int target = 0;
res = _3Sum(array, target);
// res = threeSum(array);
System.out.println(res);
}}
TwoSum(LeetCode - 1)借助HashMap实现
题目链接:https://leetcode.com/problems/two-sum/description/
题意:
给你一个数组(元素各不相同)和一个target数,找出数组中两个数之和等于target的数,返回他们的下标。保证只有一个组数据满足答案要求。
解体思路:
import java.util.Arrays;
import java.util.HashMap;
public class LeetCode_1_TwoSum {
public static int[] TwoSum(int[] nums, int target) {
int[] index = new int[] {-1,-1};
HashMap<Integer,Integer> hashMap = new HashMap<>(); //因为数据值不会相同,所以可以使用HashMap,如果有重复的数据,使用HashMap就会有数据丢失。
int len = nums.length;
//首先把nums[i]和对应的下标存储在HashMap中,为后面寻找ans是否存在做铺垫。
for(int i = 0; i < len; i++) {
hashMap.put(nums[i], i);
}
for(int i = 0; i < len; i++) {
int ans = target - nums[i];
//利用HashMap的containsKey()方法,可以找出答案,ans + nums[i] == target,遍历所有的nums[i],如果hashMap中有ans,那么就找到答案了,O(n)的时间复杂度就可以解决。
if(hashMap.containsKey(ans) && hashMap.get(ans) != i) {
index[0] = i;
index[1] = hashMap.get(ans);
}
}
return index;
}
public static void main(String[] args) {
int[] nums = new int[]{2, 7, 11, 15};
int target = 9;
int[] ans = new int[2];
ans = TwoSum(nums, target);
System.out.println(Arrays.toString(ans));
}
}
KSum:(递归)
解体思路:
递归出口:2sum Problem
递归:Reduce K sum problem to K – 1 sum Problem
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
public class KSum {
public List<List<Integer>> fourSum(int[] nums, int target) {
Arrays.sort(nums);
return kSum(nums, 0, 4, target);
}
private List<List<Integer>> kSum (int[] nums, int start, int k, int target) {
int len = nums.length;
List<List<Integer>> res = new ArrayList<List<Integer>>();
if(k == 2) { //twoSum: two pointers from left and right
int left = start, right = len - 1;
while(left < right) {
int sum = nums[left] + nums[right];
if(sum == target) {
List<Integer> path = new ArrayList<Integer>();
path.add(nums[left]);
path.add(nums[right]);
res.add(path);
while(left < right && nums[left] == nums[left + 1]) left++;
while(left < right && nums[right] == nums[right - 1]) right--;
left++;
right--;
} else if (sum < target) { //move left
left++;
} else { //move right
right--;
}
}
} else {
for(int i = start; i < len - (k - 1); i++) {
if(i > start && nums[i] == nums[i - 1]) continue;
List<List<Integer>> temp = kSum(nums, i + 1, k - 1, target - nums[i]);
for(List<Integer> t : temp) {
t.add(0, nums[i]);
}
res.addAll(temp);
}
}
return res;
}
public static void main(String[] args) {
int[] nums = new int[]{1, 0, -1, 0, -2, 2};
int target = 0;
List<List<Integer>> res = new LinkedList<>();
KSum kSum = new KSum();
res = kSum.fourSum(nums, target);
System.out.println(res);
}
}