2.12 快速寻找满足条件的两个数
2.12 快速寻找满足条件的两个数
基本问题:能否快速的从数组中找出两个数字,使得这两个数字的和等于一个给定的数字,为了简化起见,我们保证这个数组中存在这样的数字。
解法
- 解法1 : 直接暴力求解
- 解法2 : 空间换时间,逆向操作,利用find,或者利用hash
- 解法3 : 先排序,然后利用双指针
拓展问题:
- 1 如果把这个题目中的两个数字改成“三个数字”或者任意个数字,你的解答是什么呢?
- 2 如果完全相等的一对数字找不到,能否找出和最接近的解
- 3 把上面两个题目综合起来,会得到这样这样一个题目,给定一个数字N,和一组数字集合S,求S中和最接近N的子集。NPC问题
// 2.12 快速寻找满足条件的两个数
import java.util.*;
import java.util.Arrays.*;
class Test{
public static void main(String[] args) {
/**
基础问题:能否快速的从数组中找出两个数字,使得这两个数字的和等于一个给定的数字,为了简化起见,我们保证这个数组中存在这样的数字。
解法:
解法1 : 直接暴力求解
解法2 : 空间换时间,逆向操作,利用find,或者利用hash
解法3 : 先排序,然后利用双指针
*/
int[] arr = new int[]{3,4,1,2,9,8,10};
// int[] res = find1(arr,7);
// int[] res = find2(arr,7);
print(arr);
int[] res = find3(arr,7);
print(res);
System.out.println(threeSum(arr,27));
System.out.println(threeSumClosest(arr,29));
}
// 辅助函数,打印数组
public static void print(int[] arr){
for(int i:arr) System.out.print(i +" ");
System.out.println();
}
/**
解法1 : 直接暴力求解
*/
public static int[] find1(int[] arr,int target){
int len = arr.length;
int[] res = new int[2];
if(len == 0) return res;
for(int i = 0;i<len;i++){
for(int j = i+1;j<len;j++){
if(arr[i] + arr[j] == target){
res[0] = arr[i];
res[1] = arr[j];
break;
}
}
}
return res;
}
/**
解法2:利用hash
*/
public static int[] find2(int[] arr,int target){
int len = arr.length;
int[] res = new int[2];
if(len == 0) return res;
HashSet<Integer> set = new HashSet<>();
for(int i:arr) set.add(i);
for(int i:arr) if(set.contains(target-i)){
res[0] = i;
res[1] = target-i;
break;
}
return res;
}
/**
解法3 : 利用双指针
*/
public static int[] find3(int[] arr,int target){
int len = arr.length;
int[] res = new int[2];
if(len == 0) return res;
int i = 0;
int j = len-1;
Arrays.sort(arr);
while(i<j){
if(arr[i] + arr[j] < target) i++;
else if(arr[i] + arr[j] > target) j--;
else{
res[0] = arr[i];
res[1] = arr[j];
break;
}
}
return res;
}
/**
拓展问题:
1 如果把这个题目中的两个数字改成“三个数字”或者任意个数字,你的解答是什么呢?
2 如果完全相等的一对数字找不到,能否找出和最接近的解
3 把上面两个题目综合起来,会得到这样这样一个题目,给定一个数字N,和一组数字集合S,求S中和最接近N的子集。
NPC问题
*/
/**
拓展问题1
如果把这个题目中的两个数字改成“三个数字”或者任意个数字,你的解答是什么呢?
*/
// leetcode 15
public static List<List<Integer>> threeSum(int[] nums,int target){
int n = nums.length;
Arrays.sort(nums);
List<List<Integer>> res = new ArrayList<List<Integer>>();
for(int i = 0;i<n;i++){
if(i > 0 && nums[i] == nums[i-1]) continue;
int twoSumTarget = target - nums[i];
int k = n-1;
for(int j = i+1;j<n;j++){
if(j>i+1 && nums[j] == nums[j-1]) continue;
while(j<k && nums[j] + nums[k] > twoSumTarget) k--;
if(j == k) break;
if(nums[j] + nums[k] == twoSumTarget){
List<Integer> list = new ArrayList<Integer>();
list.add(nums[i]);
list.add(nums[j]);
list.add(nums[k]);
res.add(list);
}
}
}
return res;
}
// 任意个数字
/**
拓展问题2
leetcode 16
如果完全相等的一对数字找不到,能否找出和最接近的解
*/
public static int threeSumClosest(int[] nums, int target) {
Arrays.sort(nums);
int n = nums.length;
int res = Integer.MAX_VALUE;
for (int i = 0; i < n; i++) {
if (i > 0 && nums[i] == nums[i - 1]) continue;
int j = i + 1, k = n - 1;
while (j < k) {
int sum = nums[i] + nums[j] + nums[k];
if (sum == target) return target;
if (Math.abs(sum - target) < Math.abs(res - target)) res = sum;
else if (sum > target) {
int k0 = k - 1;
while (j < k0 && nums[k0] == nums[k]) k0--;
k = k0;
}
else {
int j0 = j + 1;
while (j0 < k && nums[j0] == nums[j]) j0++;
j = j0;
}
}
}
return res;
}
/**
拓展问题3
把上面两个题目综合起来,会得到这样这样一个题目,给定一个数字N,和一组数字集合S,求S中和最接近N的子集。
NPC问题
*/
}
Saying Less Doing More