1 排序 O(nlogn)
2 建最大堆,插入新元素的同时,不断删除最大元素O(nlogk)
3 Selection Rank 算法,注意partition方法,极其容易写错!我会另外写一篇专门讲这个算法!
更新:已经写了:http://blog.youkuaiyun.com/fightforyourdream/article/details/21373279
package Hard;
import java.util.Arrays;
import CtCILibrary.AssortedMethods;
/**
* Describe an algorithm to find the smallest 1 million numbers in 1 billion numbers. Assume that the computer memory can hold all one billion numbers.
译文:
描述一个算法,在10亿个数中找到最小的1百万个数。假设内存可以一次性装入这10亿个数。
*
*/
public class S18_6 {
class Parts {
public int left;
public int right;
public Parts(int l, int r) {
left = l;
right = r;
}
}
// 直接排序后取前requiredCount个元素
public static int rankB(int[] array, int requiredCount) {
int[] cloned = array.clone();
Arrays.sort(cloned);
return cloned[requiredCount];
}
public static void swap(int[] array, int i, int j) {
int t = array[i];
array[i] = array[j];
array[j] = t;
}
public static boolean validate(int[] array, int left, int right, int pivot,
int endLeft) {
for (int i = left; i <= endLeft; i++) {
if (array[i] > pivot) {
return false;
}
}
for (int i = endLeft + 1; i <= right; i++) {
if (array[i] <= pivot) {
return false;
}
}
return true;
}
public static boolean validateFull(int[] array) {
for (int i = 0; i < array.length; i++) {
for (int j = i; j < array.length; j++) {
for (int k = i; k <= j; k++) {
int[] cloned = array.clone();
int pivot = array[k];
int p = partition(cloned, i, j, pivot);
if (!validate(cloned, i, j, pivot, p)) {
AssortedMethods.printIntArray(cloned);
String val = p >= 0 && p < cloned.length ? String
.valueOf(array[i]) : "?";
System.out.println("pivot: " + pivot + " | " + p
+ " | " + val);
return false;
}
}
}
}
return true;
}
public static boolean isUnique(int[] array) {
int[] cloned = array.clone();
Arrays.sort(cloned);
for (int i = 1; i < cloned.length; i++) {
if (cloned[i] == cloned[i - 1]) {
return false;
}
}
return true;
}
public static int max(int[] array, int left, int right) {
int max = Integer.MIN_VALUE;
for (int i = left; i <= right; i++) {
max = Math.max(array[i], max);
}
return max;
}
public static int randomInt(int n) {
return (int) (Math.random() * n);
}
public static int randomIntInRange(int min, int max) {
return randomInt(max + 1 - min) + min;
}
// 调整array使得pivot左边都是比pivot小的,pivot右边都是比pivot大的
public static int partition(int[] array, int left, int right, int pivot) {
while (true) {
while (left <= right && array[left] <= pivot) {
left++;
}
while (left <= right && array[right] > pivot) {
right--;
}
if (left > right) {
return left - 1;
}
swap(array, left, right);
}
}
// 容易写错!! O(n)
public static int rank(int[] array, int left, int right, int requiredCount) {
int pivot = array[randomIntInRange(left, right)]; // 选择一个pivot
int leftEnd = partition(array, left, right, pivot); // returns end of left partition
int leftSize = leftEnd - left + 1; // 左半边比pivot小的数
if (leftSize == requiredCount + 1) { // 满足条件
return max(array, left, leftEnd);
} else if (requiredCount < leftSize) { // leftSize多了,在leftSize区间中partition
return rank(array, left, leftEnd, requiredCount);
} else { // leftSize小了,在leftEnd右侧继续partition
return rank(array, leftEnd + 1, right, requiredCount - leftSize);
}
}
public static void main(String[] args) {
int numberOfTests = 1000;
int count = 0;
while (count < numberOfTests) {
// 建一个包含10个范围在[-1000,1000]的随机数的数组
int[] array = AssortedMethods.randomArray(10, -1000, 1000);
if (isUnique(array)) {
int requiredCount = AssortedMethods.randomIntInRange(0, array.length - 1); // 按照递增排序,选择前n个数
int rank1 = rank(array.clone(), 0, array.length - 1, requiredCount);
int rank2 = rankB(array.clone(), requiredCount);
if (rank1 != rank2) {
System.out.println("ERROR: " + rank1 + " " + rank2);
AssortedMethods.printIntArray(array);
}
count++;
}
}
System.out.println("Completed " + count + " runs.");
}
}