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