第1题 top k问题

1.题目

给定一个数组,找出其中最小的K个数。例如数组元素是4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4。如果K>数组的长度,那么返回一个空的数组。

示例1

输入   [4,5,1,6,2,7,3,8],4

返回值 [1,2,3,4]

2.解决方案

2.1 排序

思路分析

先对输入的n个数从小到大排序,然后输出前k个数。

时空复杂度分析

T(n)=O(nlogn)

S(n)=O(1)

2.2 partition

思路分析

基于快速排序的partition函数来解决这个问题。

定义问题为f(a[],i,j,k),对数组a[]ij的数字获取最小的k个数。

step.1

p=partition(a[],i,j)

step.2

如果p-i+1=k,输出a[i~p]

如果p-i+1>k,则应该在a[i~p]范围内找top k,执行f(a,i,p,k)

如果p-i+1<k,则应该在a[p~j]范围内找top [k-(p-i+1)],执行f(a,p+1,j,k-p+i-1)

时空复杂度分析

T(n)=O(n)

S(n)=O(1)

优缺点分析

缺点

需要修改输入的数据

2.3 适合海量数据的解法

思路分析

维护一个存储k个数字的容器,从数据中先顺序读入k个数字到容器中,然后依次读入每一个数字e

如果e>=容器中最大的数,则e一定不是top k,接着读下一个

如果e<容器中最大的数,则删除容器中最大的数字,插入数字e

这个容器采用最大堆来实现操作效率最高,每次插入的时间复杂度为O(logk);

这个容器采用数组来实现,每次插入的时间复杂度为O(k)

时空复杂度分析

T(n)=O(nlogk)

S(n)=O(1)

优缺点分析

优点:

1.不修改输入数据

2.适合海量数据的输入

3.代码

public class NC119 {
    public static ArrayList<Integer> result=new ArrayList<Integer>();

    public static int partition(int [] input,int i,int j){
        int h=j;
        int l=i;
        while(h>l) {
            while (input[h] > input[l] && h > l) h--;
            if (input[h] <= input[l] && h > l) {
                int tmp = input[l];
                input[l] = input[h];
                input[h] = tmp;
                l++;
            }
            while (input[l] <= input[h] && h > l) l++;
            if (input[l] > input[h] && h > l) {
                int tmp = input[l];
                input[l] = input[h];
                input[h] = tmp;
                h--;
            }
        }
        return h;
    }

    public static void f(int [] input,int i,int j,int k) {
        if(j-i+1>k) {
            int p = partition(input, i, j);
            if (p - i + 1 == k) {
                for (int q = i; q <= p; q++) {
                    result.add(input[q]);
                }
            }else if(p - i + 1 == k+1){
                for (int q = i; q < p; q++) {
                    result.add(input[q]);
                }
            }
            else if (p - i + 1 > k+1) {
                f(input, i, p - 1, k);
            } else {
                for (int q = i; q <= p; q++) {
                    result.add(input[q]);
                }
                f(input, p + 1, j, k - p + i - 1);
            }
        }else if(j-i+1==k){
            for(int q=i;q<=j;q++){
                result.add(input[q]);
            }
        }
    }
}

猜你喜欢

转载自blog.csdn.net/wzl1217333452/article/details/115451037
今日推荐