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.

181 lines
4.6 KiB

2 years ago
package class24;
import java.util.Arrays;
import java.util.Comparator;
public class Code02_KthMinPair {
public static class Pair {
public int x;
public int y;
Pair(int a, int b) {
x = a;
y = b;
}
}
public static class PairComparator implements Comparator<Pair> {
@Override
public int compare(Pair arg0, Pair arg1) {
return arg0.x != arg1.x ? arg0.x - arg1.x : arg0.y - arg1.y;
}
}
// O(N^2 * log (N^2))的复杂度,你肯定过不了
// 返回的int[] 长度是2{3,1} int[2] = [3,1]
public static int[] kthMinPair1(int[] arr, int k) {
int N = arr.length;
if (k > N * N) {
return null;
}
Pair[] pairs = new Pair[N * N];
int index = 0;
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
pairs[index++] = new Pair(arr[i], arr[j]);
}
}
Arrays.sort(pairs, new PairComparator());
return new int[] { pairs[k - 1].x, pairs[k - 1].y };
}
// O(N*logN)的复杂度,你肯定过了
public static int[] kthMinPair2(int[] arr, int k) {
int N = arr.length;
if (k > N * N) {
return null;
}
// O(N*logN)
Arrays.sort(arr);
// 第K小的数值对第一维数字是什么 是arr中
int fristNum = arr[(k - 1) / N];
int lessFristNumSize = 0;// 数出比fristNum小的数有几个
int fristNumSize = 0; // 数出==fristNum的数有几个
// <= fristNum
for (int i = 0; i < N && arr[i] <= fristNum; i++) {
if (arr[i] < fristNum) {
lessFristNumSize++;
} else {
fristNumSize++;
}
}
int rest = k - (lessFristNumSize * N);
return new int[] { fristNum, arr[(rest - 1) / fristNumSize] };
}
// O(N)的复杂度,你肯定蒙了
public static int[] kthMinPair3(int[] arr, int k) {
int N = arr.length;
if (k > N * N) {
return null;
}
// 在无序数组中找到第K小的数返回值
// 第K小以1作为开始
int fristNum = getMinKth(arr, (k - 1) / N);
// 第1维数字
int lessFristNumSize = 0;
int fristNumSize = 0;
for (int i = 0; i < N; i++) {
if (arr[i] < fristNum) {
lessFristNumSize++;
}
if (arr[i] == fristNum) {
fristNumSize++;
}
}
int rest = k - (lessFristNumSize * N);
return new int[] { fristNum, getMinKth(arr, (rest - 1) / fristNumSize) };
}
// 改写快排时间复杂度O(N)
// 在无序数组arr中找到如果排序的话arr[index]的数是什么?
public static int getMinKth(int[] arr, int index) {
int L = 0;
int R = arr.length - 1;
int pivot = 0;
int[] range = null;
while (L < R) {
pivot = arr[L + (int) (Math.random() * (R - L + 1))];
range = partition(arr, L, R, pivot);
if (index < range[0]) {
R = range[0] - 1;
} else if (index > range[1]) {
L = range[1] + 1;
} else {
return pivot;
}
}
return arr[L];
}
public static int[] partition(int[] arr, int L, int R, int pivot) {
int less = L - 1;
int more = R + 1;
int cur = L;
while (cur < more) {
if (arr[cur] < pivot) {
swap(arr, ++less, cur++);
} else if (arr[cur] > pivot) {
swap(arr, cur, --more);
} else {
cur++;
}
}
return new int[] { less + 1, more - 1 };
}
public static void swap(int[] arr, int i, int j) {
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
// 为了测试,生成值也随机,长度也随机的随机数组
public static int[] getRandomArray(int max, int len) {
int[] arr = new int[(int) (Math.random() * len) + 1];
for (int i = 0; i < arr.length; i++) {
arr[i] = (int) (Math.random() * max) - (int) (Math.random() * max);
}
return arr;
}
// 为了测试
public static int[] copyArray(int[] arr) {
if (arr == null) {
return null;
}
int[] res = new int[arr.length];
for (int i = 0; i < arr.length; i++) {
res[i] = arr[i];
}
return res;
}
// 随机测试了百万组,保证三种方法都是对的
public static void main(String[] args) {
int max = 100;
int len = 30;
int testTimes = 100000;
System.out.println("test bagin, test times : " + testTimes);
for (int i = 0; i < testTimes; i++) {
int[] arr = getRandomArray(max, len);
int[] arr1 = copyArray(arr);
int[] arr2 = copyArray(arr);
int[] arr3 = copyArray(arr);
int N = arr.length * arr.length;
int k = (int) (Math.random() * N) + 1;
int[] ans1 = kthMinPair1(arr1, k);
int[] ans2 = kthMinPair2(arr2, k);
int[] ans3 = kthMinPair3(arr3, k);
if (ans1[0] != ans2[0] || ans2[0] != ans3[0] || ans1[1] != ans2[1] || ans2[1] != ans3[1]) {
System.out.println("Oops!");
}
}
System.out.println("test finish");
}
}