• top-k问题详解——通过堆解决高频面试题


    目录

    500家公司求出前100强

    500家公司里最后100家公司

    前五百家公司,第一百强的公司

      面试题



    500家公司求出前100强

            典型的top-k问题可以通过建立堆(优先级队列)来实现,在500家公司求出前100强的问题当中,可以建立一个大根堆,这样你可以通过弹出堆顶的元素存入数组来记录前一百强公司,因为大根堆堆顶元素为最大值,每弹出一次,都会再次调整为大根堆,这样就可以保证每次弹出都是目前堆中最大的元素。(不是很好的做法,下面还有更好的做法

    代码如下:

    1. import java.util.Arrays;
    2. import java.util.Comparator;
    3. import java.util.PriorityQueue;
    4. public class Test {
    5. /**
    6. * array为500家公司
    7. * store为待存入的前100强公司
    8. * k为求入前几强
    9. */
    10. public static void top10(int[] array, int[]store, int k){
    11. PriorityQueue priorityQueue = new PriorityQueue(new Comparator() {
    12. @Override
    13. public int compare (Integer o1, Integer o2){
    14. return o2 - o1;
    15. }
    16. });
    17. for(int i = 0; i < array.length; i++){
    18. priorityQueue.offer(array[i]);
    19. }
    20. for(int i = 0; i < k; i++){
    21. store[i] = priorityQueue.poll();
    22. }
    23. }
    24. public static void main(String[] args){
    25. /**
    26. * 测试用例
    27. * 假设有10家公司,求前5家
    28. */
    29. int[] array = {3,1,2,9,6,7,8,4,5,10};
    30. int[] store = new int[5];
    31. top10(array, store, 5);
    32. System.out.println(Arrays.toString(store));
    33. }
    34. }

            实际上这样写还不是很好的办法,当公司的数量特别大时,每进行一次调整都可能浪费很多时间,所以,其实可以建立一个大小为100的小根堆,先将数组的前100个元素放入,再将后面的元素与堆顶元素比较,若比堆顶元素大,则存入,最后剩下堆中的元素就是前100强公司。

            代码如下:

    1. import java.util.Arrays;
    2. import java.util.Comparator;
    3. import java.util.PriorityQueue;
    4. public class Test {
    5. /**
    6. * array为500家公司
    7. * k为前100强的
    8. */
    9. public static int[] top10(int[] array, int k){
    10. int[] ret = new int[k];
    11. PriorityQueue priorityQueue = new PriorityQueue(new Comparator() {
    12. @Override
    13. public int compare (Integer o1, Integer o2){
    14. return o1 - o2;
    15. }
    16. });
    17. for(int i = 0; i < array.length; i++){
    18. if(priorityQueue.size() < k){
    19. priorityQueue.offer(array[i]);
    20. }else{
    21. if(priorityQueue.peek() < array[i]){
    22. priorityQueue.poll();
    23. priorityQueue.offer(array[i]);
    24. }
    25. }
    26. }
    27. for(int i = 0; i < k ; i++){
    28. ret[i] = priorityQueue.poll();
    29. }
    30. return ret;
    31. }
    32. public static void main(String[] args){
    33. /**
    34. * 测试用例
    35. * 假设有10家公司,求前三家强的公司
    36. */
    37. int[] array = {3,1,2,9,6,7,8,4,5,10};
    38. int[] store = top10(array, 3);
    39. System.out.println(Arrays.toString(store));
    40. }
    41. }


    500家公司里最后100家公司

            由上例不难想出,只需要将大根堆修改成小根堆,比较值修改即可

    如下代码:

    1. import java.util.Arrays;
    2. import java.util.Comparator;
    3. import java.util.PriorityQueue;
    4. public class Test {
    5. /**
    6. * array为500家公司
    7. * k为后100弱的
    8. */
    9. public static int[] top10(int[] array, int k){
    10. int[] ret = new int[k];
    11. PriorityQueue priorityQueue = new PriorityQueue(new Comparator() {
    12. @Override
    13. public int compare (Integer o1, Integer o2){
    14. return o2 - o1;
    15. }
    16. });
    17. for(int i = 0; i < array.length; i++){
    18. if(priorityQueue.size() < k){
    19. priorityQueue.offer(array[i]);
    20. }else{
    21. if(priorityQueue.peek() > array[i]){
    22. priorityQueue.poll();
    23. priorityQueue.offer(array[i]);
    24. }
    25. }
    26. }
    27. for(int i = 0; i < k ; i++){
    28. ret[i] = priorityQueue.poll();
    29. }
    30. return ret;
    31. }
    32. public static void main(String[] args){
    33. /**
    34. * 测试用例
    35. * 假设有10家公司,求后三家公司
    36. */
    37. int[] array = {3,1,2,9,6,7,8,4,5,10};
    38. int[] store = top10(array, 3);
    39. System.out.println(Arrays.toString(store));
    40. }
    41. }

    前五百家公司,第一百强的公司

            不可以直接排序,如何用堆的思想实现呢?可能你是想建立一个大根堆,然后弹出前99家公司,然后,再弹出一家便是你的所求吗?想象一下,每弹出一次,都有可能会进行向下调整,时间复杂度立马就上来了;要是求第100强的可以建立一个大小为100的小根堆,这样堆顶元素不就是第一百强了吗?建立了大小为100的小根堆后,再将数组的一百个元素放入内,再将数组剩下的元素与堆顶元素进行比较,如果比他大则交换。

    代码如下:

    1. import java.util.Comparator;
    2. import java.util.PriorityQueue;
    3. public class Test {
    4. /**
    5. * array为500家公司
    6. * k为第几强的公司
    7. */
    8. public static int top10(int[] array, int k){
    9. PriorityQueue priorityQueue = new PriorityQueue(new Comparator() {
    10. @Override
    11. public int compare (Integer o1, Integer o2){
    12. return o1 - o2;
    13. }
    14. });
    15. for(int i = 0; i < array.length; i++){
    16. if(priorityQueue.size() < k){
    17. priorityQueue.offer(array[i]);
    18. }else{
    19. if(priorityQueue.peek() < array[i]){
    20. priorityQueue.poll();
    21. priorityQueue.offer(array[i]);
    22. }
    23. }
    24. }
    25. return priorityQueue.peek();
    26. }
    27. public static void main(String[] args){
    28. /**
    29. * 测试用例
    30. * 假设有10家公司,求第3强
    31. */
    32. int[] array = {3,1,2,9,6,7,8,4,5,10};
    33. int top3 = top10(array, 3);
    34. System.out.println(top3);
    35. }
    36. }

      面试题

             和上例中前强500家公司位于后面的100家公司是一个道理,但要注意的是小心此题k = 0的情况。

    如下代码:

    1. class Solution {
    2. public int[] smallestK(int[] arr, int k) {
    3. int[] ret = new int[k];
    4. if(k == 0){
    5. return ret;
    6. }
    7. PriorityQueue priorityQueue = new PriorityQueue(new Comparator() {
    8. @Override
    9. public int compare (Integer o1, Integer o2){
    10. return o2 - o1;
    11. }
    12. });
    13. for(int i = 0; i < arr.length; i++){
    14. if(priorityQueue.size() < k){
    15. priorityQueue.offer(arr[i]);
    16. }else{
    17. if(priorityQueue.peek() > arr[i]){
    18. priorityQueue.poll();
    19. priorityQueue.offer(arr[i]);
    20. }
    21. }
    22. }
    23. for(int i = 0; i < k ; i++){
    24. ret[i] = priorityQueue.poll();
    25. }
    26. return ret;
    27. }
    28. }

     

  • 相关阅读:
    用三种方式安装Nginx
    PHP使用阿里云对象存储oss
    OSError: [WinError 1455] 页面文件太小,无法完成操作 报错解决
    k8s环境部署配置
    linux parted 方式挂盘,支持大于4T盘扩容
    ChatGPT高效提问—prompt实践(白领助手)
    web安全学习笔记【11】——信息打点(1)
    gitlab访问报错: Whoops, GitLab is taking too much time to respond
    .NET delegate 委托 、 Event 事件,接口回调
    biggan:large scale gan training for high fidelity natural image synthesis
  • 原文地址:https://blog.csdn.net/CYK_byte/article/details/126207184