最小的K个数

从“数组中出现次数超过一半的数字”得到启发,同样可以基于Partition函数来解决。


一、O(n)算法

void GetLeastNumbers(int *input, int n, int *output, int k)
{
      if (input == NULL || output == NULL || k > n || n <= 0 || k <= 0)
            return;
      int start = 0;
      int end = n - 1;
      int index = Partition(input, start, end);
      while (index != k -1)
      {
           if (index > k - 1)
           {
                 end = index - 1;
                 index = Partition(input, start, end);
           }
           else
           {
                start = index + 1;
                index = Partition(input, start, end);
           }
      }
      for (int i = 0; i < k; ++i)
           output[i] = input[i];
}


二、O(nlogK)算法


可以先创建一个大小为K的数据容器来存储最小的K个数字,姐下来我们每次从输入的n个整数中读入一个数。如果容器中已有的数字少于k个,则直接把这次读入的整数放入容器中;如果容器中已有k个数,也就是容器已满,此时我们不能再插入新的数字而只能替换已有的数字。找出这已有的k个数的最大值,然后拿这次待插入的整数和最大值进行比较。如果待插入的值比当前已有的最大值还要大,那么直接丢弃。

很容易想到最大堆,于是我们每次可以在O(1)得到已有的k个数字的最大值,但需要O(logk)时间完成删除及插入操作


// “下沉”,位置pos处开始

void sink(int pos, int A[], int N)
{
       init j;
       while (2 * pos <= N)
       {
            j = 2 * pos;
           if (j < N && A[j] <= A[j+1])
                 j++;
           if (A[pos] >= A[j])
                break;
           swap(A, pos, j);
           pos = j; // “下沉”到其子节点
      }
}

// array:输入数组

// A[0]未用

for   i = 0    to   K

A[i+1] = array[i]

end for


// 建立大根堆:将数组中的前K个元素构建成一个最大堆

void BuildHeap(int A[], int K) // K个元素,完全二叉树存储
{
       for (int i = K / 2; i >= 1; --i)
       {
             sink(i, A, K);
        }
}

//  数组后面的元素,往最大堆插入(待插元素比堆顶元素小) 或者  丢弃(待插元素大于堆顶元素)

for  i = K + 1    to       N

if  array[i] < A[1]

A[1] = array[i]

sink(1, A,  K)

end if

end for


二、利用STL set和multiset(允许重复)底层基于红黑树实现的机制

typedef multiset<int, greater<int> > intset; // 按从大到小排序
typedef multiset<int, greater<int> >::iterator setIterator;

void GetLeasetNumbers(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)
        {
              // 前k个元素直接插入到容器中
             if ((leastNumbers.size()) < k)
                   leastNumbers.insert(*iter);
             else
             {
                  setIterator iterGreatest = leastNumbers.begin();

                  if (*iter < *(leastNumbers.begin()))
                  {
                       leastNumbers.erase(iterGreatest);
                       leastNumbers.insert(*iter);
                  }
              }
         }
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值