深夜来到校花学姐家,帮她解决了TopK,她竟然......

Posted CRUD速写大师

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了深夜来到校花学姐家,帮她解决了TopK,她竟然......相关的知识,希望对你有一定的参考价值。


学姐在此!!!

深夜,当我正在梦中快乐的与校花学姐玩耍时,一阵响铃把我吵醒,我XX的你个XX的,让我看看是哪个玩意敢打扰我与校花学姐嬉戏。
我打开手机一看,【此时停顿3秒】,再擦擦眼睛再看,是她是她就是她,我的校花学姐,QAQ,我颤颤巍巍的接通了电话,只听见那边传来甜美的声音说道:皮皮虾,TopK要怎么解决啊,这两天都快被问疯了!都睡不着了。我连忙说到行啊行啊,那我去你家???,学姐道:行啊,你快点哦。我说一定一定,说完挂断电话,直接一个弹射起床,收拾好后连忙来到学姐家,开始了深夜交流,🤣🤣🤣

在这里插入图片描述

在这里插入图片描述


我说想要解决TopK问题,首先的话,你需要去熟练掌握两种排序算法,①、快速排序,②、堆排序。



快速排序

快速排序的基本思想:

  1. 先从数列中取出一个数作为基准数
  2. 分区过程,将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边(或者相反,根据需要升序还是降序来)
  3. 再对左右区间重复第二步,直到各区间只有一个数
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("排序前:");
        System.out.println(Arrays.toString(arr));
        quickSort(arr, 0, arr.length - 1);
        System.out.print("排序后:");
        System.out.println(Arrays.toString(arr));
    }
}

在这里插入图片描述




快排优化(三分取中法)

对于一些特殊的数据,比如整体上来说几乎有序的数据,在使用普通的快排会非常慢,此时我们就需要优化!

采用三数取中法,也就是取左端、中间、右端三个数,然后进行排序,确保中间值最小,然后将中间数作为枢纽值。

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);
        // 保证中间较小
        if (arr[mid] > arr[end])
            swap(arr, mid, end);
        // 保证中间最小,左右最大
        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;
    }

}

堆排序

堆排序的思想

  1. 先将待排序的序列建成大根堆,使得每个父节点的元素大于等于它的子节点。
  2. 此时整个序列最大值即为堆顶元素,我们将其与末尾元素交换,使末尾元素为最大值。
  3. 然后再调整堆顶元素使得剩下的 n-1 个元素仍为大根堆,再重复执行以上操作我们即能得到一个有序的序列。

小顶堆与之相反

堆实际上是一棵完全二叉树,其任何一非叶节点满足性质:

heap[i] <= heap[2i+1] && heap[i] <= heap[2i+2] 或者 heap[i] >= heap[2i+1] && heap >= heap[2i+2]

即任何一非叶节点的关键字不大于或者不小于其左右孩子节点的关键字。


大顶堆

public class Main {


    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 = {1,2,4,0,3,-1,6,2};

        System.out.println("堆排序前:" + Arrays.toString(a));

        heapSort(a,a.length);

        System.out.println("堆排序后:" + Arrays.toString(a));
    }

}

在这里插入图片描述


小顶堆

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("堆排序前:" + Arrays.toString(a));

        heapSort(a,a.length);

        System.out.println("堆排序后:" + Arrays.toString(a));
    }

}

在这里插入图片描述




解决TopK问题


利用快速排序分区思想找第 K 小元素

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) {
        // 每快排切分1次,找到排序后下标为 mid 的元素,如果 mid 恰好等于 k 就返回 mid 以及 mid 左边所有的数;
        int mid = getMiddle(arr, begin, end);

        if (mid == k) {
            System.out.println(Arrays.toString(arr));
            return;
        }
		
        //根据 mid 和 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("第3大元素为:" + topK);
    }
}

在这里插入图片描述



快排获取最小的 K 个元素

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就是第k个元素的下标,我们要返回前k个元素
        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;
            }
            //根据 mid 和 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[s

以上是关于深夜来到校花学姐家,帮她解决了TopK,她竟然......的主要内容,如果未能解决你的问题,请参考以下文章

我的 Serverless 实战—深夜,校花师姐找到我,这件事说起来有点羞羞

学妹跑过来问我为啥Xshell 打不开了,让我帮她处理下手把手讲解

熬夜帮学姐用Python完成词云图,没想到我好兄弟竟然...

熬夜帮学姐用Python完成词云图,没想到我好兄弟竟然...

这样给小白讲原码反码补码,帮她彻底解决困扰了三天的问题

Python带来的福利:隔壁清纯小姐姐晚上敲我门,要我帮她解决人生大事