Byte boss asked me TopK. I'll backhand. I have several solutions. Which one do you want?

Posted by reversenorm on Thu, 20 Jan 2022 22:13:10 +0100

I said that to solve the TopK problem, first of all, you need to master two sorting algorithms: ①, quick sorting and ②, heap sorting.

Quick sort

Basic idea of quick sort:

  1. First, take a number from the sequence as the reference number
  2. In the partitioning process, all numbers larger than this number are placed on its right, and all numbers less than or equal to it are placed on its left (or vice versa, in ascending or descending order as needed)
  3. Repeat the second step for the left and right intervals until there is only one number in each interval
import java.util.Arrays;

public class sorts {

    public static void quickSort(int[] arr, int begin, int end) {
        if (begin < end) {
            int mid = getMiddle(arr, begin, end);
            quickSort(arr, begin, mid);
            quickSort(arr, mid + 1, end);
        }
    }

    private static int getMiddle(int[] arr, int begin, int end) {
        int mid = arr[begin];
        int left = begin;
        int right = end;
        while (left < right) {
            while (left < right && mid <= arr[right]) {
                right--;
            }
            arr[left] = arr[right];
            while (left < right && mid >= arr[left]) {
                left++;
            }
            arr[right] = arr[left];
        }
        arr[left] = mid;

        return left;
    }


    public static void main(String[] args) {
        int[] arr = {1, 2, 3, 4, 5, 6, 7, 6, 5, 4, 3, 2, 1};
        System.out.print("Before sorting:");
        System.out.println(Arrays.toString(arr));
        quickSort(arr, 0, arr.length - 1);
        System.out.print("After sorting:");
        System.out.println(Arrays.toString(arr));
    }
} 

Fast scheduling optimization (middle trisection method)

For some special data, such as almost ordered data on the whole, it will be very slow to use ordinary fast scheduling. At this time, we need to optimize!

Adopt the three number middle method, that is, take the left, middle and right numbers, and then sort them to ensure the minimum middle value, and then take the middle number as the hub value.

public class Main {

    public void quickSort(int[] arr, int k,int start,int end) {
        if (start < end) {
            int mid = getMiddle(arr,start,end);
            quickSort(arr,k,start,mid - 1);
            quickSort(arr,k,mid + 1,end);
        }
    }
    
    private int getMiddle(int[] arr, int start, int end) {
        int mid = start + (end - start) / 2;
        if (arr[start] > arr[end])
            swap(arr, start, end);
        // Ensure that the middle is small
        if (arr[mid] > arr[end])
            swap(arr, mid, end);
        // Ensure the minimum in the middle and the maximum in the left and right
        if (arr[mid] > arr[start])
            swap(arr, start, mid);


        int left = start;
        int right = end;
        int pivot = arr[left];

        while (left < right) {
            while(left < right && arr[right] >= pivot) {
                right--;
            }
            arr[left] = arr[right];
            while (left < right && arr[left] <= pivot) {
                left++;
            }
            arr[right] = arr[left];
        }
        arr[left] = pivot;
        return left;
    }

    private void swap(int[] arr, int i, int j) {
        int tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp;
    }

} 

Heap sort

The idea of heap sorting

  1. First, build the sequence to be sorted into a large root heap so that the element of each parent node is greater than or equal to its child nodes.
  2. At this time, the maximum value of the whole sequence is the top element of the heap. We exchange it with the last element to make the last element the maximum value.
  3. Then adjust the top elements so that the remaining n-1 elements are still large root heap. Repeat the above operations to get an ordered sequence.

The small top pile is the opposite

Heap is actually a complete binary tree, and any non leaf node satisfies the following properties:

Heap [i] < = heap [2I + 1] & & heap [i] < = heap [2I + 2] or heap [i] > = heap [2I + 1] & & heap > = heap [2I + 2]

That is, the keyword of any non leaf node is not greater than or less than the keyword of its left and right child nodes.

Small top pile

public class Main {


    public static void heapSort(int[] arr,int heapSize) {
        //Float up
        for (int i = heapSize / 2 - 1; i >= 0; i--) {
            builderHeap(arr,i,arr.length);
        }

        //sink
        for (int i = heapSize - 1; i >= 0; i--) {
            swap(arr,0,i);
            builderHeap(arr,0,i);
        }

    }

    private static void swap(int[] arr, int i, int j) {
        int tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp;
    }


    private static void builderHeap(int[] arr, int index, int length) {

        //Current node
        int tmp = arr[index];
        //Left child node
        for (int i = index * 2 + 1; i < length; i = i * 2 + 1) {
            //If the value of the right child node is greater than the left child node
            if (i + 1 < length && arr[i + 1] > arr[i]) {
                i++;
            }

            //If the maximum value of the left child node and the right child node is greater than the parent node, the exchange is performed
            if (arr[i] > tmp) {
                arr[index] = arr[i];
                index = i;
            }else
                break;
        }
        arr[index] = tmp;
    }

    public static void main(String[] args) {
        int[] a = {1,2,4,0,3,-1,6,2};

        System.out.println("Before heap sorting:" + Arrays.toString(a));

        heapSort(a,a.length);

        System.out.println("After heap sorting:" + Arrays.toString(a));
    }

} 

Large top pile

public class sorts {


    public static void heapSort(int[] arr,int heapSize) {
        for (int i = heapSize / 2 - 1; i >= 0; i--) {
            builderHeap(arr,i,arr.length);
        }

        for (int i = heapSize - 1; i >= 0; i--) {
            swap(arr,0,i);
            builderHeap(arr,0,i);
        }

    }

    private static void swap(int[] arr, int i, int j) {
        int tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp;
    }


    private static void builderHeap(int[] arr, int index, int length) {

        int tmp = arr[index];

        for (int i = index * 2 + 1; i < length; i = i * 2 + 1) {

            if (i + 1 < length && arr[i + 1] < arr[i]) {
                i++;
            }

            if (arr[i] < tmp) {
                arr[index] = arr[i];
                index = i;
            }else
                break;
        }
        arr[index] = tmp;
    }

    public static void main(String[] args) {
        int[] a = {3,2,1,5,6,4};

        System.out.println("Before heap sorting:" + Arrays.toString(a));

        heapSort(a,a.length);

        System.out.println("After heap sorting:" + Arrays.toString(a));
    }

} 

Solve the TopK problem

Using the idea of quick sorting partition to find the K-th small element

import java.util.Arrays;

/**
 * @author dong
 * @date 2021/4/8 19:41
 */
public class sorts {


    public static int getTopK(int[] arr, int k) {
        quickSort(arr, 0, arr.length - 1, k - 1);
        return arr[k - 1];
    }

    public static void quickSort(int[] arr, int begin, int end, int k) {
        // Split every fast row once, find the sorted element with the subscript mid, and return mid and all numbers to the left of mid if mid is exactly equal to k;
        int mid = getMiddle(arr, begin, end);

        if (mid == k) {
            System.out.println(Arrays.toString(arr));
            return;
        }
		
        //Determine whether to continue to segment the left segment or the right segment according to the size of mid and k.
        if (k > mid) {
            quickSort(arr, mid + 1, end, k);
        } else
            quickSort(arr, begin, mid - 1, k);
    }

    private static int getMiddle(int[] arr, int begin, int end) {
        int mid = arr[begin];
        int left = begin;
        int right = end;
        while (left < right) {
            while (left < right && mid <= arr[right]) {
                right--;
            }
            arr[left] = arr[right];
            while (left < right && mid >= arr[left]) {
                left++;
            }
            arr[right] = arr[left];
        }
        arr[left] = mid;

        return left;
    }


    public static void main(String[] args) {
        int[] arr = {1, 2, 3, 4, 5, 6, 7, 6, 5, 4, 3, 2, 1};
        int topK = getTopK(arr, 3);
        System.out.println("The third element is:" + topK);
    }
} 

Get the minimum K elements in quick row

public class Main {

    public static int[] getLeastNumbers(int[] arr, int k) {
        int len = arr.length;
        if (len == 0 || k == 0) return new int[0];
        //k - 1 is the subscript of the k-th element. We want to return the first k elements
        quickSort(arr,0,arr.length - 1,k);
        int[] res = new int[k];
        for(int i = 0;i < k;i++) {
            res[i] = arr[i];
        }
        return res;
    }

    public static void quickSort(int[] arr,int start,int end,int k) {
        if (start < end) {
            int mid = getMiddle(arr,start,end);
            if (mid == k) {
                return;
            }
            //Determine whether to continue to segment the left segment or the right segment according to the size of mid and k.
            if (k > mid) {
                quickSort(arr, mid + 1, end, k);
            } else
                quickSort(arr, start, mid - 1, k);
        }
    }

    private static int getMiddle(int[] arr, int start, int end) {
        int mid = start + (end - start) / 2;
        if (arr[start] > arr[end]) {
            swap(arr,start,end);
        }
        if (arr[mid] > arr[end]) {
            swap(arr,mid,end);
        }
        if (arr[mid] > arr[start]) {
            swap(arr,start,mid);
        }

        int pivot = arr[start];
        int left = start;
        int right = end;

        while (left < right) {
            while (left < right && arr[right] >= pivot) {
                right--;
            }
            arr[left] = arr[right];
            while (left < right && arr[left] <= pivot) {
                left++;
            }
            arr[right] = arr[left];
        }
        arr[left] = pivot;
        return left;
    }

    private static void swap(int[] arr, int i, int j) {
        int tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp;
    }

    public static void main(String[] args) {
        int[] arr = {2,5,4,10,1,0,6,9,8,-2};
        System.out.println(Arrays.toString(arr));
        int k = 4;
        int[] res = getLeastNumbers(arr, k);
        System.out.println("least" + k + "Elements:" + Arrays.toString(res));
    }

} 

Construct a fixed heap to solve the minimum K elements

To get the maximum K elements, let's build a large top heap

public class Main {



    private static int[] topK(int[] data, int k) {
        int[] topK = new int[k];

        //Construct fixed size heap
        for (int i = 0; i < k; i++) {
            topK[i] = data[i];
        }

        buildHeap(topK);

        for (int i = k; i < data.length; i++) {
            int root = topK[0];
            //If it is smaller than the top element
            if (data[i] < root) {
                topK[0] = data[i];
                heapify(topK,0,topK.length);
            }
        }
        return topK;
    }

    private static void buildHeap(int[] data) {
        //Traverse the child and push the parent from the subscript of the last parent node: (data.length - 1 - 1)/2
        int heapSize = data.length;
        for (int i = heapSize / 2 - 1; i >= 0; i--) {
            heapify(data,i,heapSize);
        }
    }

    private static void heapify(int[] arr,int index,int len) {
        int tmp = arr[index];

        for (int i = index * 2 + 1; i < len; i = i * 2 + 1) {
            if (i + 1 < len && arr[i + 1] > arr[i]) {
                i += 1;
            }
            if (arr[i] > tmp) {
                arr[index] = arr[i];
                index = i;
            }else
                break;
        }
        arr[index] = tmp;
    }

    //test
    public static void main(String[] args) {
        int[] data = {12, 10, 4, 7, 30, 9, 6, 20};
        int[] topK = topK(data, 3);

        System.out.println(Arrays.toString(topK));
    }

} 

Construct a fixed heap to solve the maximum K elements

To get the maximum K elements, let's build a small top heap

public class MinHeap {


    private static int[] topK(int[] data, int k) {
        int[] topK = new int[k];

        //Construct fixed size heap
        for (int i = 0; i < k; i++) {
            topK[i] = data[i];
        }

        buildHeap(topK);

        for (int i = k; i < data.length; i++) {
            int root = topK[0];
            //If it is larger than the top element
            if (data[i] > root) {
                topK[0] = data[i];
                //Rebuild heap
                heapify(topK,0,topK.length);
            }
        }
        return topK;
    }

    private static void buildHeap(int[] data) {
        //Traverse the child and push the parent from the subscript of the last parent node: (data.length - 1 - 1)/2
        int heapSize = data.length;
        for (int i = heapSize / 2 - 1; i >= 0; i--) {
            heapify(data,i,heapSize);
        }
    }

    private static void heapify(int[] arr,int index,int len) {
        int tmp = arr[index];

        for (int i = index * 2 + 1; i < len; i = i * 2 + 1) {
            if (i + 1 < len && arr[i + 1] < arr[i]) {
                i += 1;
            }
            if (arr[i] < tmp) {
                arr[index] = arr[i];
                index = i;
            }else
                break;
        }
        arr[index] = tmp;
    }

    //test
    public static void main(String[] args) {
        int[] data = {12, 10, 4, 7,11, 30, 9, 6, 20};
        int[] topK = topK(data, 5);

        System.out.println(Arrays.toString(topK));
    }

} 

summary

Some time ago, I studied with some awesome leaders. We spent three months together to sort out the learning materials about Java and share them with our little partners who want to learn java together. We can learn together, make progress together, get promoted and get a raise together

***

java learning content

Sorting of core knowledge points

1000 questions, 946 pages, interview questions for Internet java engineers

Java learning video

If you feel that your learning efficiency is low and you lack correct guidance, you can join the technology circle with rich resources and strong learning atmosphere to learn and communicate together!

[JAVA advanced group]

There are many technical giants from the front line in the group, as well as code farmers struggling in small factories or outsourcing companies. We are committed to building an equal and high-quality JAVA Communication circle, which may not make everyone's technology advance by leaps and bounds in the short term, but in the long run, vision, pattern and long-term development direction are the most important.

Topics: Java Programmer