Three solutions to the topk problem (including the dichotomy solution)!

1. Judgment is made according to the partition function of the divide and conquer method used in quicksort.

    A. If the partition returns the value index<k, then use the divide and conquer method at the index index+1 -> high.

    B. If the partition returns the value index>=k, then use the divide and conquer method at the index low -> index-1.

    C. Until index = k - 1, return the number with subscript k-1.

    The time complexity is O(n), and the space complexity is O(1). But this method changes the position of the numbers in the array. .

public class Main {
	public static void topk1(int[] input, int k) {		
		if(input.length == 0){
			System.out.println("input.length == 0!!");
			return;
		}
		if(k>input.length){
			System.out.println("k > input.length!!");
			return;
		}
		
		int index = partition(input, 0, input.length-1);
		while(index != k - 1){
			if(index > k-1)index = partition(input, 0, index-1);
			if(index < k-1)index = partition(input, index+1, input.length-1);
		}
		
		for (int i = 0; i < k; i++) {
			System.out.println(input[i]);
		}
	}
	
	public static int partition(int[] input, int start ,int end) {
		
		int pivot = input[start];
		int low = start, high = end;
		
		while(low < high){
			while(low<high&&input[high]<=pivot)high--;
			if(low<high){
				input[low] = input[high];
				low++;
			}
			while(low<high&&input[low]>pivot)low++;
			if(low<high){
				input[high] = input[low];
				high--;
			}
		}
		input[low] = pivot;
		return low;
	}
}

2. Use the min heap to find the largest K number.

    A. We first need to create a heap of size K. If we want the space complexity to be O(1), we can build a heap in the first k spaces in the original array. But this way we change the position of the numbers in the original array. If we don't want to change the position of the numbers in the original array, we can create a container of size K, but the space complexity is O(k).

    B. Then we compare each number nums[i] from the k+1th number to the last number with the min heap, and if it is greater than the top element of the heap, replace the top element of the heap with nums[i].

    C. Adjust the min heap.

    Time complexity O(nlogk), space complexity O(k) (do not change the position of array elements) or O(1) (change the position of array elements)

public class Main {
	//---------------------------------Minimum heap------------ ----------------------------
	
	public static void topk3(int[] input, int k) {
		if(input.length == 0){
			System.out.println("input.length == 0!!");
			return;
		}
		if(k>input.length){
			System.out.println("k > input.length!!");
			return;
		}
		buildMinHeap(input, k);

		for (int i = k; i < input.length; i++) {
			if(input[i] > input[0]){
				swap(input, i, 0);
				MinHeapFixedDown (input, k, 0);
			}
		}
		for (int i = 0; i < k; i++) {
			System.out.println(input[i]);
		}
	}
	public static void buildMinHeap(int[] input, int k) {
		for(int i = k/2-1;i >= 0;i--){
			MinHeapFixedDown (input, k, i);
		}
	}
	public static void MinHeapFixedDown(int[] input, int k, int i) {
		int left = 2*i+1, right = left + 1;
		if((left < k && input[i] > input[left]) || ((right < k && input[i] > input[right]))){
			if(right < k &&input[left] > input[right]){
				swap(input, i, right);
				MinHeapFixedDown (input, k, right);
			}else {
				swap(input, i, left);
				MinHeapFixedDown (input, k, left);
			}
		}
	}
	private static void swap(int[] input, int i, int j) {
		int temp = input[i];
		input[i] = input[j];
		input[j] = temp;
	}
}

3. Dichotomy to find the top K numbers.

    What if we want to neither change the position of the array elements nor open up space? We can use dichotomy.

    Time complexity O(nlog(max-min)), space complexity O(1).

public class Main {
	public static void topk3(int[] input, int k) {
		// Judge special input
		if(input.length == 0){
			System.out.println("input is null!!!");
			return;
		}
		if(k>input.length){
			System.out.println("k must be below length!!!");
			return;
		}
		
		//find max and min
		int low = Integer.MAX_VALUE;
		int high = Integer.MIN_VALUE;
		for (int i = 0; i < input.length; i++) {
			if(input[i] > high)high = input[i];
			if(input[i] < low)low = input[i];
		}
		//count is used to count the number of numbers greater than mid and less than high
		int count = 0;
		// Dichotomy core code
		while(true){		
			int mid = (low + high)/2;			
			count = count(input, mid, high);				
			if(count > k)low = mid+1;			
			else if(count < k){
				k = k - count;
				high =mid - 1;
				mid = low;
			}			
			else {
				for (int i = 0; i < input.length; i++) {
					if(input[i]>=mid)System.out.println(input[i]);
				}			
				return;
			}
		}
	}
	// count the number of numbers between two numbers in the array
	public static int count(int[] input, int start, int end) {
		int count = 0;
		for(int i = 0;i < input.length;i++)
			if(input[i] >= start && input[i]<= end)
				count++;
		return count;	
	}
}


Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=326855622&siteId=291194637