[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);
}

一旦找到了第i个最小的数字后,就可以遍历整个数组来找所有小于等于该数字的元素。当数组有重复元素的话,需要修改一些地方,但是时间就不能保证是线性的了。其实也有算法能线性时间内处理有重复的数组,但是比较复杂,有兴趣的请自行搜索研究。

CareerCup All in One 题目汇总

时间: 2024-12-06 20:55:53

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

[CareerCup] 18.1 Add Two Numbers 两数相加

18.1 Write a function that adds two numbers. You should not use + or any arithmetic operators. 这道题让我们实现两数相加,但是不能用加号或者其他什么数学运算符号,那么我们只能回归计算机运算的本质,位操作Bit Manipulation,我们在做加法运算的时候,每位相加之后可能会有进位Carry产生,然后在下一位计算时需要加上进位一起运算,那么我们能不能将两部分拆开呢,我们来看一个例子759+674 1.

[CareerCup] 18.9 Find and Maintain the Median Value 寻找和维护中位数

18.9 Numbers are randomly generated and passed to a method. Write a program to find and maintain the median value as new values are generated. LeetCode上的原题,请参见我之前的博客Find Median from Data Stream. 解法一: priority_queue<int> small; priority_queue<int,

[CareerCup] 18.4 Count Number of Two 统计数字2的个数

18.4 Write a method to count the number of 2s between 0 and n. 这道题给了我们一个整数n,让我们求[0,n]区间内所有2出现的个数,比如如果n=20,那么满足题意的是2, 12, 20,那么返回3即可.LeetCode上有一道很类似的题Factorial Trailing Zeroes,但是那道题求5的个数还包括了因子中的5,比如10里面也有5,这是两题的不同之处.那么首先这题可以用brute force来解,我们对区间内的每一个数字

[CareerCup] 18.10 Word Transform 单词转换

18.10 Given two words of equal length that are in a dictionary, write a method to transform one word into another word by changing only one letter at a time. The new word you get in each step must be in the dictionary. 这道题让我们将一个单词转换成另一个单词,每次只能改变一个字母,

[CareerCup] 18.11 Maximum Subsquare 最大子方形

18.11 Imagine you have a square matrix, where each cell (pixel) is either black or white. Design an algorithm to find the maximum subsquare such that all four borders are filled with black pixels. LeetCode上的原题,请参见我之前的解法Maximal Square.书上给了两种解法,但是比较长:

[CareerCup] 18.3 Randomly Generate Integers 随机生成数字

18.3 Write a method to randomly generate a set of m integers from an array of size n. Each element must have equal probability of being chosen. 这道题让我们从一个数组中随机取出m个数字,要求每个数字被取出的概率相同,其实这道题用的是之前那道18.2 Shuffle Cards的方法,同样我们可以用递归和迭代两种方法来做,递归的思路还用的回溯法,回溯到i+

[CareerCup] 18.8 Search String 搜索字符串

18.8 Given a string s and an array of smaller strings T, design a method to search s for each small string in T. class SuffixTreeNode { public: unordered_map<char, SuffixTreeNode*> children; char value; vector<int> indexes; void insertString(s

[CareerCup] 18.2 Shuffle Cards 洗牌

18.2 Write a method to shuffle a deck of cards. It must be a perfect shuffle—in other words, each of the 52! permutations of the deck has to be equally likely. Assume that you are given a random number generator which is perfect. 这道题让我们实现一个洗牌的算法,实际上洗

[CareerCup] 18.12 Largest Sum Submatrix 和最大的子矩阵

18.12 Given an NxN matrix of positive and negative integers, write code to find the submatrix with the largest possible sum. 这道求和最大的子矩阵,跟LeetCode上的Maximum Size Subarray Sum Equals k和Maximum Subarray很类似.这道题不建议使用brute force的方法,因为实在是不高效,我们需要借鉴上面LeetCode