求长度为n的序列中最大的m个数

思路1:最小堆,时间复杂度O(nlogm)
分析:
1、建一个大小为m的最小堆,最小的元素在根部
2、遍历序列,若元素大于根部元素,则用该元素替换根部元素,并对最小堆进行调整,若元素小于等于根部元素,则不对最小堆做任何改变,这样遍历完整个序列后堆中的元素就是最大的m个元素

public class T1 
{   
    public static void main(String[] args) 
    {
        Scanner in=new Scanner(System.in);
        while(in.hasNext())
        {
            int n=in.nextInt();
            int m=in.nextInt();
            int[] arr=new int[n];
            for(int i=0;i<n;i++)
            {
                arr[i]=in.nextInt();
            }
            solve(arr, m);
        }
    }
    static void  minHeap(int[] arr,int len,boolean isOnlyRoot)
    {
        int s=isOnlyRoot?0:len/2-1;
        int d=0;
        for(int i=s;i>=d;i--)
        {
            int k=i;
            for(int j=2*k+1;j<len;k=j,j=2*k+1)
            {
                if(j+1<len && arr[j+1]<arr[j])
                {
                    j=j+1;
                }
                if(arr[k]>arr[j])
                {
                    swap(arr, k, j);
                }
                else
                {
                    break;
                }
            }
        }
    }
    static void solve(int[] arr,int m)
    {
        minHeap(arr, m, false);
        for(int i=m;i<arr.length;i++)
        {
            if(arr[i]>arr[0])
            {
                arr[0]=arr[i];
                minHeap(arr, m, true);
            }
        }
        for(int i=0;i<m;i++)
        {
            System.out.println(arr[i]+" ");
        }
    }
    static void swap(int[] arr,int i,int j)
    {
        arr[i]=arr[i]+arr[j];
        arr[j]=arr[i]-arr[j];
        arr[i]=arr[i]-arr[j];
    }
}

思路2:快排,时间复杂度O(n)
分析:
假如能找到第m大的元素,并且将比该元素大的放在左边,比该元素小的放在右边,那么问题也就解决了。通过快排可以做这一点。如何做呢?
1:得到索引i,比a[i]的在其左边,比a[i]小的在其右边。根据i的值分别执行以下操作。
2:若i>m,则说明第m大的元素在a[i]左边,此时需要从i左边的元素中找出第m大的元素,即对i左边区域进行步骤1
3、若i﹤m-1,则说明第m大的元素在a[i]右边,此时需要从i的右边的元素中找出第m大的元素,即对i右边的原色进行步骤1
4、若i==m-1或者i==m,则说明a[i-1]为第m大的元素,或者最大的m个元素在i左边,整个过程到这里结束。
时间复杂度计算:(n+n/2+n/4+…..)=O(n)

import java.util.Scanner;

public class T2 {

    public static void main(String[] args)
    {
        Scanner in=new Scanner(System.in);
        while(in.hasNext())
        {
            int n=in.nextInt();
            int m=in.nextInt();
            int[] arr=new int[n];
            for(int i=0;i<n;i++)
            {
                arr[i]=in.nextInt();
            }
            findMaxM(arr, 0, n-1, m);
            for(int i=0;i<m;i++)
            {
                System.out.print(arr[i]+" ");
            }
        }
    }
    static int quick(int[] arr,int l,int r)//大的放左边,小的放右边
    {
        int x=arr[l];
        int i=l;
        int j=r;
        while(true)
        {
            while(i<j && arr[j]<=x)
                j--;
            if(i<j)
            {
                arr[i]=arr[j];
                i++;
            }else
                break;
            while(i<j && arr[i]>=x)
                i++;
            if(i<j)
            {
                arr[j]=arr[i];
                j--;
            }else 
                break;
        }
        arr[i]=x;
        return i;
    }
    static void findMaxM(int[] arr,int l,int r,int m)
    {
        if(l>=r)
            return;
        int mid=quick(arr, l, r);
        if(mid==m-1||mid==m)
            return;
        else if(mid>m)
            findMaxM(arr, l, mid-1, m);
        else if (mid<m-1) 
            findMaxM(arr, mid+1, r, m);
    }
}
点赞