zoukankan      html  css  js  c++  java
  • 第k大的数

    题目描述

    给定一个数组a和数字k,找出a中第k大的数。

    方法一:快排思想

    找到一个枢轴,枢轴右边还有k-1个数即可。因为每次遍历只选择一边,因而降低了时间复杂度。

    public class Main {
    
        public static int kthBiggest (int[]a,int k,int low,int high) {
            int left=low,right=high,pivot=a[left];
            while(left<right){
                while(left<right&&a[right]>=pivot) right--;
                if(left<right) {
                    a[left] = a[right];
                    left++;
                }
                while(left<right&&a[left]<=pivot) left++;
                if(left<right) {
                    a[right] = a[left];
                    right--;
                }
            }
            a[left]=pivot;
            if(high-left>k-1) return kthBiggest(a,k,left+1,high);
            else if(high-left<k-1) return kthBiggest(a,k-(high-left+1),low,left-1);
            else return pivot;
        }
    
        public static void main(String[] args) {
            int[] a={3,5,4,8,9,1,0,7,2,6};
            System.out.println(kthBiggest(a,4,0,a.length-1));
        }
    }
    

    时间复杂度分析:时间复杂度为O(n)。第一次遍历长度为n,接下来每一次遍历的长度都是上一次的长度乘以一个随机比例。

    方法二:基于冒泡排序和简单选择排序

    并不需要将完整的数组排完序。选择这两种排序算法的原因是它们都是先选择数组中最大的数,然后是次大的数,以此类推。因此外层循环只用执行k次即可达到目标。
    冒泡法:

     public static int bubble (int[]a,int k) {
            int n=a.length;
            for(int i=0;i<k;++i)
                for(int j=n-1;j>i;--j){
                    if(a[j]>a[j-1]){
                        int temp=a[j];
                        a[j]=a[j-1];
                        a[j-1]=temp;
                    }
                }
            return a[k-1];
     }
    

    选择法:

    public static int select(int[] a,int k){
            int n=a.length,m,i,j;
            for(i=0;i<k;++i) {
                m=i;//m为第i轮遍历剩余元素中最大元素的下标
                for (j = i + 1; j < n; ++j) {
                    if(a[j]>a[m]) m=j;
                }
                int temp=a[j];
                a[j]=a[m];
                a[m]=temp;
            }
            return a[k-1];
    }
    

    时间复杂度分析:两种算法时间复杂度均为O(n*k)。

    方法三:自行构建最大堆

    如果使用函数库中的优先队列,则需要更高的空间复杂度。可以在自行构建最大堆,在原数组自身上操作。另外也没有必要将整个数组排好序,堆排序也是依次选出剩余元素中的最大值,执行k次该操作即可。
    因为原数组下标从0开始,所以根节点下标为0。有:i结点的左孩子2i+1,右孩子2i+2, index结点的父亲:(index-1)/2

        //堆调整操作,用于建堆
        //cur为当前节点位置,n为当前堆中的元素个数-1
        public static void adjust(int[]a,int cur,int n){
            int temp=a[cur];
            for(int i=cur*2+1;i<=n;i=2*i+1){
                if(i<n&&a[i]<a[i+1]) i++;
                if(a[i]<=temp) break;
                a[cur]=a[i];
                cur=i;
            }
            a[cur]=temp;
    }
    
     public static int heapKth(int[] a,int k){
            int n=a.length-1;
            //将元素组构建为堆
            //最后一个节点下标为n,最后一个非叶节点下标为(n-1)/2。
            for(int i=(n-1)/2;i>=0;--i) adjust(a,i,n);
            for(int i=n;i>n-k;--i){
                //堆中剩余元素的最大值放到数组尾部。
                //完全二叉树的最后一个节点移至堆顶。
                int temp=a[i];
                a[i]=a[0];
                a[0]=temp;
                //根节点的左右子树均为堆,将根节点调整到适当位置后,整棵树仍然是一个堆。
                adjust(a,0,i-1);
            }
            return a[n-k+1];
    }
    

    时间复杂度分析:复杂度为O(nlogn),由建堆的过程决定。

  • 相关阅读:
    Atitit  atiMail atiDns新特性 v2  q39
    Atitit  atiMail atiDns新特性 v2  q39
    Atitit.aticmd v4  新特性q39 添加定时器释放功能
    Atitit.aticmd v4  新特性q39 添加定时器释放功能
    Atitit. Atiposter 发帖机 新特性 poster new feature   v7 q39
    Atitit. Atiposter 发帖机 新特性 poster new feature   v7 q39
    Atitit.编程语言and 自然语言的比较and 编程语言未来的发展
    Atitit.编程语言and 自然语言的比较and 编程语言未来的发展
    atitit.解决struts2 SpringObjectFactory.getClassInstance NullPointerException  v2 q31
    知也atitit.解决struts2 SpringObjectFactory.getClassInstance NullPointerException  v2 q31无涯 - I
  • 原文地址:https://www.cnblogs.com/Frank-Hong/p/14038968.html
Copyright © 2011-2022 走看看