DAY1 快速排序+第K大的数字

2020-04-19  本文已影响0人  神游物外的轮子

剑指Offer 39:数组中出现超过一半的数字

解法一中提到Partition方法,出自快速排序
选中数组中随机一个数字,将小于它的数字排到左边,大于它的数字排到右边

int Partition(int data[], int length, int start, int end)
{
    if (data == nullptr || length <= 0 || start < 0 || end >= length)
        throw new std:exception("Invalid Parameters");

    int i = RandomInRange(start, end);
    Swap(&data[i], &data[end]);

    // small代表最后一个小于选中数的位置
    int small = start - 1;
    for (i = start; i < end; i++)
    {
        if (data[i] < data[end])
        {
            small++;
            // 中间有大于选中的数字
            if (i != small)
                Swap(&data[i], &data[small]);
        }
    }
    // 这里small自增是为了交换大数和末尾的选中数字
    small++;
    Swap(&data[small], &data[end]);
    return small;
}

使用以上的方法,可以类似二分的找到中位数,而中位数就是数组中超过一半的数,复杂度为\sum_{i=0}(\frac{n}{2})^i
相关问题: 找到数组中第k大的数字,复杂度为O(n)


第二种解法保存两个数字,分别为当前数字以及连续出现次数
好处在于代码结构简单,且不修改原始数据

剑指Offer 40:最小的k个数

排序的复杂度为O(n\log{n}),使用Partition方法可以将复杂度降到O(n)
另一种解法是维护一个长度为k的池子,依次比较现有池子和下一个数字的大小关系,维护这个池子

typedef multiset<int, greater<int>> intSet;
typedef multiset<int, greater<int>>::iterator setIterator;

void GetLeastNumbers(const vector<int> &data, intSet& leastNumbers, int k)
{
    leastNumbers.clear();
    if (k < 1 || data.size() < k)
        return;

    vector<int>::const_iterator iter = data.begin();
    for (; iter != data.end; iter++)
    {
        if (leastNumbers.size() < k)
        {
            leastNumbers.insert(*iter);
        }
        else if (leastNumbers.size() == k && *iter < *(leastNumbers.begin()))
        {
            leastNumbers.erase(leastNumbers.begin());
            leastNumbers.insert(*iter);
        }
    }
}
上一篇下一篇

猜你喜欢

热点阅读