• 获取一个数组里面第K大的元素


    如何在O(n)内获取一个数组比如{9, 1, 2, 8, 7, 3, 6, 4, 3, 5, 0, 9, 19, 39, 25, 34, 17, 24, 23, 34, 20}里面第K大的元素呢?

    我们可以使用类似快排的分区方式,将第K大的元素限定在数组的左边或右边,递归求取。

     

    我的Java代码实现如下:

     1 package com.structure.sort;
     2 
     3 /**
     4  * @author zhangxingrui
     5  * @create 2019-01-27 22:52
     6  **/
     7 public class QuickSort {
     8 
     9     public static void main(String[] args) {
    10         int[] numbers = {9, 1, 2, 8, 7, 3, 6, 4, 3, 5, 0, 9, 19, 39, 25, 34, 17, 24, 23, 34, 20};
    11 //        int[] numbers = {3,1,2};
    12         // 快速排序借助递归来实现,重要的是要找到递归的终结条件(不然容易发生堆栈异常)
    13         // 递推公式:quickSort(p...r) = merge(p, q - 1) + merge(q+1, r)
    14         // 终结条件:p >= r
    15         /*quickSort(numbers, 0, numbers.length - 1);
    16         for (int number : numbers) {
    17             System.out.println(number);
    18         }*/
    19 
    20         int k = getK(4, numbers, 0, numbers.length - 1);
    21         System.out.println(k);
    22     }
    23 
    24     private static void quickSort(int[] numbers, int p, int r){
    25         if(p >= r)
    26             return;
    27         int q = partition(numbers, p, r, false);
    28         quickSort(numbers, p, q - 1);
    29         quickSort(numbers, q + 1, r);
    30     }
    31 
    32     /**
    33      * @Author: xingrui
    34      * @Description: 分区
    35      * @Date: 23:13 2019/1/27
    36      */
    37     private static int partition(int[] numbers, int p, int r, boolean isAsc){
    38         int k = numbers[r];
    39         int i = p;
    40 
    41         if(isAsc){
    42             for (int j = p; j <= r; ++j) {
    43                 if(numbers[j] < k){
    44                     int temp = numbers[i];
    45                     numbers[i] = numbers[j];
    46                     numbers[j] = temp;
    47                     i++;
    48                 }
    49             }
    50             numbers[r] = numbers[i];
    51             numbers[i] = k;
    52             return i;
    53         }else{
    54             for (int j = p; j <= r; ++j) {
    55                 if(numbers[j] > k){
    56                     int temp = numbers[i];
    57                     numbers[i] = numbers[j];
    58                     numbers[j] = temp;
    59                     i++;
    60                 }
    61             }
    62             numbers[r] = numbers[i];
    63             numbers[i] = k;
    64             return i;
    65         }
    66 
    67     }
    68 
    69     /**
    70      * @Author: xingrui
    71      * @Description: 获取第K大的元素
    72      * @Date: 23:15 2019/1/29
    73      */
    74     private static int getK(int k, int[] numbers, int p, int r){
    75         int q = partition(numbers, p, r, false);
    76 
    77         if(q + 1 == k)
    78             return numbers[q];
    79 
    80         if(q + 1 > k){
    81             return getK(k, numbers, p, q - 1);
    82         }else{
    83             return getK(k, numbers, q + 1, r);
    84         }
    85     }
    86 
    87 }

    原理就是我们先任取一个数作为分区的数,把大于它的数放在它的左边,小于它的数放在它的右边。

    假设我们有数组array[p...r],那么第一次分区之后就形成了array[p...q-1],q,array[q+1...r]三个部分,如果我们要求取第3大的元素,

    那么就将3与q+1做比较,

    如果3==q+1,那么说明array[p...q-1]里面只有两个元素且都>array[q],而array[q+1,r]都<q,所以array[q]

    就是第三大的元素;

    如果3 > q+1,说明array[p...q-1]里面的元素只有一个元素,所以我们需要到array[q+1...r]里面再去找;

    如果3 < q+1,则说明array[p...q-1]里面有三个元素,所以我们还需要到array[p...q-1]里面去找。

     

    这样的话,每次只会到分区的一半的数组里面去找:n/2 + n/4 + n/8 + 直到区间缩小为1,最终可得2n - 1,

    所以这样做的时间复杂的就是O(n)。

  • 相关阅读:
    IDEA SpringBoot项目连接数据库报Acess denied错误解决方法
    字符流中出现的第一个字符
    数组中重复的数字
    替换空格
    数组中次数超过一半的数字
    表示数值的字符串
    正则表达式匹配
    SpringMVC中的视图和视图解析器
    IntelliJ Idea取消Could not autowire. No beans of 'xxxx' type found的错误提示
    spring中注解注入 context:component-scan 的使用说明
  • 原文地址:https://www.cnblogs.com/alinainai/p/10336412.html
Copyright © 2020-2023  润新知