剑指offer 最小的k个数

题目描述

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

 

解法一:根据快速排序,基于数组的第k个数字来调整,使得k左边的数字都小于k,k右边的数字都大于k。

调整后,左边的k个数字就是最小的k个数字,时间复杂度O(n)。

/**
 * @author yuan
 * @date 2019/2/19
 * @description 基于partition,时间复杂度O(n)
 */
public class 最小的K个数 {
    public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
        ArrayList<Integer> result = new ArrayList<>(input.length);
        if (k < 1 || k > input.length) {
            return result;
        }
        int l = 0, r = input.length - 1;
        int index = partition(input, l, r);
        while (index != k - 1) {
            if (index > k - 1) {
                r = index - 1;
                index = partition(input, l, r);
            } else {
                l = index + 1;
                index = partition(input, l, r);
            }
        }
        for (int i = 0; i < k; i++) {
            result.add(input[i]);
        }
        return result;
    }

    /**
     * 切片
     * @param a
     * @param left
     * @param right
     * @return
     */
    private int partition(int[] a, int left, int right) {
        int i = left, j = right;
        int base = a[left];
        while (i < j) {
            while (i < j && a[j] >= base) {
                --j;
            }
            while (i < j && a[i] <= base) {
                ++i;
            }
            swap(a, i, j);
        }
        swap(a, left, i);
        return i;
    }

    private void swap(int[] a, int i, int j) {
        int temp = a[i];
        a[i] = a[j];
        a[j] = temp;
    }
}

 

解法二:用最大堆,时间复杂度O(nlgk)

先创建一个大小为k的堆,接下来每次读取一个整数,当堆的数字小于k,直接放入堆中。

若堆已经有k个数字,将堆中最大的值和当前整数比较,如果当前整数小于堆的最大值,则将堆中的最大值替换为当前整数。

如果当前整数比堆的最大值大,则不可能是最小的k个整数之一,直接抛弃。


/**
 * @author yuan
 * @date 2019/2/19
 * @description 最大堆,时间复杂度O(nlgk)
 * 用最大堆保存这k个数,每次只和堆顶比,如果比堆顶(堆中最大的元素)小,删除堆顶,新数入堆。
 * 否则抛弃
 */
public class 最小的K个数 {
    public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
        ArrayList<Integer> result = new ArrayList<>(input.length);
        int len = input.length;
        if (k > len || k < 1) {
            return result;
        }
        PriorityQueue<Integer> maxHeap = new PriorityQueue<>(k, Comparator.reverseOrder());
        for (int i = 0; i < len; i++) {
            if (maxHeap.size() < k) {
                maxHeap.offer(input[i]);
            } else if (input[i] < maxHeap.peek()) {
                // 如果当前整数比堆中最大的元素还小,用这个整数替换已有的最大值
                maxHeap.poll();
                maxHeap.offer(input[i]);
            }
        }
        result.addAll(maxHeap);
        return result;
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值