package class48; import java.util.Arrays; // 来自学员问题 // 比如{ 5, 3, 1, 4 } // 全部数字对是:(5,3)、(5,1)、(5,4)、(3,1)、(3,4)、(1,4) // 数字对的差值绝对值: 2、4、1、2、1、3 // 差值绝对值排序后:1、1、2、2、3、4 // 给定一个数组arr,和一个正数k // 返回arr中所有数字对差值的绝对值,第k小的是多少 // arr = { 5, 3, 1, 4 }, k = 4 // 返回2 public class Code01_MinKthPairMinusABS { // 暴力解,生成所有数字对差值绝对值,排序,拿出第k个,k从1开始 public static int kthABS1(int[] arr, int k) { int n = arr.length; int m = ((n - 1) * n) >> 1; if (m == 0 || k < 1 || k > m) { return -1; } int[] abs = new int[m]; int size = 0; for (int i = 0; i < n; i++) { for (int j = i + 1; j < n; j++) { abs[size++] = Math.abs(arr[i] - arr[j]); } } Arrays.sort(abs); return abs[k - 1]; } // 二分 + 不回退 public static int kthABS2(int[] arr, int k) { int n = arr.length; if (n < 2 || k < 1 || k > ((n * (n - 1)) >> 1)) { return -1; } Arrays.sort(arr); // 0 ~ 大-小 二分 // l ~ r int left = 0; int right = arr[n - 1] - arr[0]; int mid = 0; int rightest = -1; while (left <= right) { mid = (left + right) / 2; // 数字对差值的绝对值<=mid的数字对个数,是不是 < k个的! if (valid(arr, mid, k)) { rightest = mid; left = mid + 1; } else { right = mid - 1; } } return rightest + 1; } // 假设arr中的所有数字对,差值绝对值<=limit的个数为x // 如果 x < k,达标,返回true // 如果 x >= k,不达标,返回false public static boolean valid(int[] arr, int limit, int k) { int x = 0; for (int l = 0, r = 1; l < arr.length; r = Math.max(r, ++l)) { while (r < arr.length && arr[r] - arr[l] <= limit) { r++; } x += r - l - 1; } return x < k; } // 为了测试 public static int[] randomArray(int n, int v) { int[] ans = new int[n]; for (int i = 0; i < ans.length; i++) { ans[i] = (int) (Math.random() * v); } return ans; } // 为了测试 public static void main(String[] args) { int size = 100; int value = 100; int testTime = 10000; System.out.println("测试开始"); for (int i = 0; i < testTime; i++) { int n = (int) (Math.random() * size); int k = (int) (Math.random() * (n * (n - 1) / 2)) + 1; int[] arr = randomArray(n, value); int ans1 = kthABS1(arr, k); int ans2 = kthABS2(arr, k); if (ans1 != ans2) { System.out.print("arr : "); for (int num : arr) { System.out.print(num + " "); } System.out.println(); System.out.println("k : " + k); System.out.println("ans1 : " + ans1); System.out.println("ans2 : " + ans2); System.out.println("出错了!"); break; } } System.out.println("测试结束"); long start; long end; int n = 500000; int v = 50000000; int[] arr = randomArray(n, v); int k = (int) (Math.random() * (n * (n - 1) / 2)) + 1; start = System.currentTimeMillis(); kthABS2(arr, k); end = System.currentTimeMillis(); System.out.println("大数据量运行时间(毫秒):" + (end - start)); } }