此总结包含题目(两数之和,三数之和,最接近的三数之和,四数之和,两数之和 II - 输入有序数组
/*
给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
*/
public int[] twoSum(int[] nums, int target) {
// map中的 key 某个之前的数 value 这个数出现的位置
HashMap<Integer,Integer> map = new HashMap<Integer,Integer>();
for(int i = 0;i < nums.length;i++){
int k = target - nums[i];
if(map.containsKey(k)){
return new int[]{map.get(k),i};
}
map.put(nums[i],i);
}
return new int[] { -1, -1 };
}
/*
给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。
*/
public List<List<Integer>> threeSum(int[] nums) {
List<List<integer>> list = new ArrayList<List<Integer>>();
Arrays.sort(nums);
for(int i = 0;i < nums.length - 2;i++){
if(nums[i]>0) break;
if(i==0||nums[i] != nums[i-1]){
List<List<integer>> tmp = mytwoSum(nums,i+1,-nums[i]);
for(List<integer> cur:tmp){
cur.add(0,nums[i]);
list.add(cur);
}
}
}
rerurn list;
}
public List<List<Integer>> mytwoSum(int[] nums, int begin, int target) {
int L = begin;
int R = nums.length-1;
List<List<Integer>> ans = new ArrayList<List<Integer>>();
while(L<R){
if(nums[L] + nums[R] < target){
L++;
}else if(nums[L] + nums[R] > target){
R--;
}else{ // 进入else表示找到了
// 1. begin是第一个开始 2. 当前和前一个不等
if(L==begin||nums[L-1] != nums[L]){
List<Integer> M = new ArrayList<Integer>();
M.add(nums[L]);
M.add(nums[R]);
ans.add(M);
}
L++;
}
}
return ans;
}
/*
给定一个包括 n 个整数的数组 nums 和 一个目标值 target。找出 nums 中的三个整数,使得它们的和与 target 最接近。返回这三个数的和。假定每组输入只存在唯一答案。
*/
public int threeSumClosest(int[] nums, int target) {
int sum1 = nums[0] + nums[1] + nums[2]; //首先随便计算三数之和
int diff = Math.abs(target - sum1); // 差值
Arrays.sort(nums);
for(int i = 0;i < nums.length - 2;i++){
if(i > 0 && nums[i-1] == nums[i]) continue;
int m = i + 1;
int n = nums.length -1;
while(m<n){
int tmp = nums[i] + nums[m] + nums[n];
int t_diff = Math.abs(target - tmp);
if(t_diff < diff){
diff = t_diff;
sum1 = tmp;
}
if(tmp < target){
m++;
}else{
n--;
}
}
}
return sum1;
}
/*
给你一个由 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
*/
public List<List<Integer>> fourSum(int[] nums, int target) {
List<List<Integer>> list = new ArrayList<List<Integer>>();
Arrays.sort(nums);
for(int i = 0;i < nums.length - 3;i++){
if(i==0||nums[i] != nums[i-1]){
List<List<Integer>> tmp = myThreeSum(nums,i+1,target-nums[i]);
for(List<Integer> cur:tmp){
cur.add(0,nums[i]);
list.add(cur);
}
}
}
return list;
}
public List<List<Integer>> myThreeSum(int[] nums, int begin, int target) {
List<List<Integer>> list = new ArrayList<List<Integer>>();
for(int i = begin;i < nums.length - 2;i++){
if(i == begin||nums[i] != nums[i-1]){
List<List<Integer>> tmp = mytwoSum(nums,i+1,target-nums[i]);
for(List<Integer> cur:tmp){
cur.add(0,nums[i]);
list.add(cur);
}
}
}
return list;
}
public List<List<Integer>> mytwoSum(int[] nums, int begin, int target) {
int L = begin;
int R = nums.length-1;
List<List<Integer>> ans = new ArrayList<List<Integer>>();
while(L<R){
if(nums[L] + nums[R] < target){
L++;
}else if(nums[L] + nums[R] > target){
R--;
}else{ // 进入else表示找到了
// 1. begin是第一个开始 2. 当前和前一个不等
if(L==begin||nums[L-1] != nums[L]){
List<Integer> M = new ArrayList<Integer>();
M.add(nums[L]);
M.add(nums[R]);
ans.add(M);
}
L++;
}
}
return ans;
}
// 解法二
public List<List<Integer>> fourSum2(int[] nums, int target) {
List<List<Integer>> list = new ArrayList<List<Integer>>();
if(nums.length<4) return list;
Arrays.sort(nums);
for(int i=0;i<nums.length-3;i++) {
if (i > 0 && nums[i] == nums[i - 1]) continue;
for(int j=i+1;j<nums.length-2;j++) {
if (j > i+1 && nums[j] == nums[j - 1]) continue;
int m = j+1;
int n = nums.length-1;
while(m<n) {
int sum = nums[i]+nums[j]+nums[m]+nums[n];
if(sum==target) {
List<Integer> tmpIntegers = new ArrayList<Integer>();
tmpIntegers.add(nums[i]);
tmpIntegers.add(nums[j]);
tmpIntegers.add(nums[m]);
tmpIntegers.add(nums[n]);
list.add(tmpIntegers);
while (m < n && nums[m] == nums[m + 1]) ++m;
while (m < n && nums[n] == nums[n - 1]) --n;
m++;
n--;
}else if (sum<target) {
m++;
}else {
n--;
}
}
}
}
return list;
}
/*
给定一个已按照 非递减顺序排列 的整数数组 numbers ,请你从数组中找出两个数满足相加之和等于目标数 target 。
函数应该以长度为 2 的整数数组的形式返回这两个数的下标值。numbers 的下标 从 1 开始计数 ,所以答案数组应当满足 1 <= answer[0] < answer[1] <= numbers.length 。
*/
public int[] twoSum(int[] numbers, int target) {
int point_i = 0;
int point_j = numbers.length-1;
while(point_i<point_j){
if(numbers[point_i]+numbers[point_j] == target) return new int[]{point_i+1,point_j+1};
else if(numbers[point_i]+numbers[point_j] < target) point_i++;
else{
point_j--;
}
}
return new int[]{point_i,point_j};
}
6. 总结
此类题目主要用到哈希表来存储元素,以达到快速判断的目的,此外还有利用已经排好序的数组后的特性,利用双指针来加速检索符合要求的元素