You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

123 lines
3.1 KiB

2 years ago
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));
}
}