Hard 找最小的k个数(Selection Rank) @CareerCup

1 排序 O(nlogn)

2 建最大堆,插入新元素的同时,不断删除最大元素O(nlogk)

3 Selection Rank 算法,注意partition方法,极其容易写错!我会另外写一篇专门讲这个算法!

更新:已经写了:http://blog.csdn.net/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.");
	}

}





你可能感兴趣的:(Hard 找最小的k个数(Selection Rank) @CareerCup)