1. 程式人生 > 實用技巧 >2.12 快速尋找滿足條件的兩個數

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問題
	*/
}