2.12 快速尋找滿足條件的兩個數
阿新 • • 發佈:2020-11-25
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問題 */ }