剑指offer——最小的K个数(堆排或partition,复习排序算法思想精髓)

题目描述
输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4。

思路:
维护一个由k个值组成的动态最大堆。然后接下来的每个数字和堆顶的数据比较,如果比堆顶的数据小,那就把数据放入堆中。最小堆内部不用严格排序,只要保证堆中最大的数字在堆顶即可。

或者直接快排,再把前n位数字输出。

import java.util.*;
public class Solution {
    public ArrayList GetLeastNumbers_Solution(int [] input, int k) {
        ArrayList list = new ArrayList<>();
        if(k<=0||k>input.length)
            return list;
        if(k>1){  // 这里先对前k个数进行堆排序,组成了一个最大堆(堆顶为最大值)
            for(int i = k/2-1; i>=0; i-- ){
            heap(input,i,k);
            }
        }
        // 然后将剩下的元素插入最大堆,方法是与堆顶的元素进行比较,如果小于堆顶元素,即插入,并维护堆
        for(int i = k; iif(input[i]0]){
                input[0] = input[i];
                heap(input,0,k);
            }
        }
        for(int i = 0; ireturn list;


        }


        public void heap(int[] input, int i, int k){
            int flag = i;
            if(2*i+1if(input[2*i+1]>input[flag])
                    flag = 2*i+1;
            }
            if(2*i+2if(input[2*i+2]>input[flag])
                    flag = 2*i+2;
            }
            if(flag!=i){
                int temp = input[i];
                input[i] = input[flag];
                input[flag] = temp;
                heap(input,flag,k);
            }
        }
}

另一种解法,基于partition的思想

因为快排每次都能得到基于分界点的数组,分界点左边的元素一定小于分界点上的元素。如果此分界点正好是k,则得到了最小的k个数。
最坏情况是,一直没有得到这个点,得到了一个部分排序的数组。但时间复杂度仍小于O(nlogn)

    public ArrayList GetLeastNumbers_Solution(int [] input, int k) {
        ArrayList list = new ArrayList<>();
        if (k <= 0 || k > input.length)
            return list;
        int start = 0;
        int end = input.length-1;
        int index = partition(input,start,end);
        while(index!=k){ // 把判断写在主函数,很好!
            if(index>k){
                end = index-1;
                index = partition(input,start,end);
            }
            if(indexindex+1;
                index = partition(input,start,end);
            }
        }
        for(int i = 0; ireturn list;
    }

    public int partition(int[] input, int start, int end){
        if(start>=end)
            return start;
        int flag = input[end];
        while(startwhile(input[start]<=flag&&startint temp = input[start];
        input[start] = input[end];
        input[end] = temp;
        while(input[end]>=flag&&end>start)
            --end;
        temp = input[start];
        input[start] = input[end];
        input[end] = temp;
        }
        return start;
    }

你可能感兴趣的:(面试算法题)