[CareerCup] 18.6 Smallest One Million Numbers 最小的一百万个数字

简介:

18.6 Describe an algorithm to find the smallest one million numbers in one billion numbers. Assume that the computer memory can hold all one billion numbers.

这道题让我们在十亿个数字中找到最小的一百万个数字,而且限定了计算机只有能存十亿个数字的内存。这题有三种解法,排序,最小堆,和选择排序。

首先来看排序方法,这种方法简单明了,就是把这十亿个数字按升序排列,然后返回前一百万个即可,时间复杂度是O(nlgn)。

然后来看最小堆做法,我们建立一个最大堆(大的数字在顶端),然后将前一百万个数字加进去。然后我们开始遍历剩下的数字,对于每一个数字,我们将其加入堆中,然后删掉堆中最大的数字。遍历接受后,我们就有了一百万个最小的数字,时间复杂度是O(nlgm),其中m是我们需要找的数字个数。

最后我们来看选择排序的方法,这种方法可以在线性时间内找到第i个最大或最小的数,如果数字都不是不同的,那么我们可以在O(n)的时间内找到第i个最小的数字,算法如下:

1. 随机选取数组中的一个数字当做pivot,然后以此来分割数组,记录分割处左边的数字的个数。

2. 如果左边正好有i个数字,那么返回左边最大的数字。

3. 如果左边数字个数大于i,那么继续在左边递归调用这个方法。

4. 如果左边数字个数小于i,那么在右边递归调用这个方法,但是此时的rank变为i - left_size。

参见代码如下:

int partition(vector<int> &array, int left, int right, int pivot) {
    while (true) {
        while (left <= right && array[left] <= pivot) ++left;
        while (left <= right && array[right] > pivot) --right;
        if (left >right) return left - 1;
        swap(array[left], array[right]);
    }
}

int find_max(vector<int> &array, int left, int right) {
    int res = INT_MIN;
    for (int i = left; i <= right; ++i) {
        res = max(res, array[i]);
    }
    return res;
}

int selection_rank(vector<int> &array, int left, int right, int rank) {
    int pivot = array[rand() % (right - left + 1) + left];
    int left_end = partition(array, left, right, pivot);
    int left_size = left_end - left + 1;
    if (left_size == rank + 1) return find_max(array, left, left_end);
    else if (rank < left_size) return selection_rank(array, left, left_end, rank);
    else return selection_rank(array, left_end + 1, right, rank - left_size);
}

本文转自博客园Grandyang的博客,原文链接:最小的一百万个数字[CareerCup] 18.6 Smallest One Million Numbers ,如需转载请自行联系原博主。

相关文章
POJ 3494 Largest Submatrix of All 1’s(单调栈)
POJ 3494 Largest Submatrix of All 1’s(单调栈)
|
人工智能 算法 JavaScript
Leedcode 327.区间和的个数:hard
Leedcode 327.区间和的个数:hard
63 0
|
Java 索引 Python
LeetCode 209:最小长度的子数组 Minimum Size Subarray Sum
给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的连续子数组。如果不存在符合条件的连续子数组,返回 0。
550 0
|
Java 数据安全/隐私保护
[LintCode] Number of Islands(岛屿个数)
描述 给一个01矩阵,求不同的岛屿的个数。 0代表海,1代表岛,如果两个1相邻,那么这两个1属于同一个岛。我们只考虑上下左右为相邻。 样例 在矩阵: [ [1, 1, 0, 0, 0], [0, 1, 0, 0, 1], [0, 0, 0, 1, 1], [0, 0, 0, 0, 0], [0, 0, 0, 0, 1] ] 中有 3 个岛。
1225 0