鱼C论坛

 找回密码
 立即注册
查看: 1932|回复: 11

[已解决]给定数组,输出数值最大的前n个

[复制链接]
发表于 2019-3-18 15:12:01 | 显示全部楼层 |阅读模式
50鱼币
算法复杂度 越高效越好
最佳答案
2019-3-18 15:12:02
思路:1.判断n与数组长度len的大小,若n>len,返回false,若n==len,返回整个数组,否则执行下一步;
2.使用哨兵min记录数组前n个数中最小的数,从数组第n+1个元素开始遍历,判断每一个数tem与min的大小,若tem小于等于min,继续遍历,
否则,将tem与min互换,并重新计算min值,继续遍历数组直到结束。最后数组前n个数既是最大的前n个数。
整个过程只需遍历一边数组,时间消耗主要在当tem>min时,即需要找到前n个数中的最小值,可以使用最小堆,时间复杂度为O(log(n)),所以整个算法时间复杂度为O(len*log(n))

最佳答案

查看完整内容

思路:1.判断n与数组长度len的大小,若n>len,返回false,若n==len,返回整个数组,否则执行下一步; 2.使用哨兵min记录数组前n个数中最小的数,从数组第n+1个元素开始遍历,判断每一个数tem与min的大小,若tem小于等于min,继续遍历, 否则,将tem与min互换,并重新计算min值,继续遍历数组直到结束。最后数组前n个数既是最大的前n个数。 整个过程只需遍历一边数组,时间消耗主要在当tem>min时,即需要找到前n个数中的最小值, ...
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2019-3-18 15:12:02 | 显示全部楼层    本楼为最佳答案   
思路:1.判断n与数组长度len的大小,若n>len,返回false,若n==len,返回整个数组,否则执行下一步;
2.使用哨兵min记录数组前n个数中最小的数,从数组第n+1个元素开始遍历,判断每一个数tem与min的大小,若tem小于等于min,继续遍历,
否则,将tem与min互换,并重新计算min值,继续遍历数组直到结束。最后数组前n个数既是最大的前n个数。
整个过程只需遍历一边数组,时间消耗主要在当tem>min时,即需要找到前n个数中的最小值,可以使用最小堆,时间复杂度为O(log(n)),所以整个算法时间复杂度为O(len*log(n))
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2019-3-18 16:04:55 | 显示全部楼层
本帖最后由 Croper 于 2019-3-18 16:09 编辑
  1. int* maxN(int* arr,int arrsize,int N) {
  2.         int* ret = new int[N + 1];
  3.         int cret = 0;
  4.         for (int i = 0; i < arrsize; ++i) {
  5.                 int num = arr[i];
  6.                 int p = 0;
  7.                 int q = cret;
  8.                 while (p < q) {
  9.                         int n = (p + q) / 2;
  10.                         if (num <= ret[n]) p = n + 1;
  11.                         else q = n;
  12.                 }

  13.                 for (int i = cret; i > q; --i) {
  14.                         ret[i] = ret[i - 1];
  15.                 }
  16.                 ret[q] = num;
  17.                 if (cret < N) ++cret;
  18.         }

  19.         return ret;
  20. }
复制代码

时间复杂度O[arr.size*N]空间复杂度O[N]
插入部分改用链表时间复杂度可达到O[arr.size*log(N)],但链表只有在数据量非常大时效率才较高,N较小时,链表效率不如直接数组
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2019-3-18 16:17:03 | 显示全部楼层
本帖最后由 jackz007 于 2019-3-18 16:22 编辑

     用 sort() 函数按从大到小排序,然后,取前 n 个即可
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>

  4. #include <time.h>

  5. void random(int array[] , const int n)
  6. {
  7.         int c , k , m                             ;
  8.         bool f                                    ;
  9.         srand(time(0))                            ;
  10.         for(k = 0 ; k < n ; k ++) array[k] = 0    ;
  11.         m = 0                                     ;
  12.         while(m < n) {
  13.                 c = rand() % n + 1                ;
  14.                 f = true                          ;
  15.                 if (m) {
  16.                         for(k = 0 ; k < m ; k ++) {
  17.                                 if (array[k] == c) {
  18.                                         f = false ;
  19.                                         break     ;
  20.                                 }
  21.                         }
  22.                 }
  23.                 if (f) array[m ++] = c             ;
  24.         }
  25. }

  26. void sort(int array[] , const int m)
  27. {
  28.         int d , i , j                           ;
  29.         for(i = 1 ; i < m ; i ++) {
  30.                 j = i                           ;
  31.                 while(j > 0 && array[j - 1] < array[j]) {
  32.                         d = array[j - 1]        ;
  33.                         array[j - 1] = array[j] ;
  34.                         array[j] = d            ;
  35.                         j --                    ;
  36.                 }
  37.         }
  38. }

  39. main(void)
  40. {
  41.         int a[5000] , i , n                           ;
  42.         random(a , 5000)                              ;
  43.         n = 50                                        ;
  44.         printf("%4d" , a[0])                          ;
  45.         for(i = 1 ; i < n ; i ++) {
  46.                 if(! (i % 10)) printf("\n%4d" , a[i]) ;
  47.                 else printf(" , %4d" , a[i])          ;
  48.         }
  49.         printf("\n\n")                                ;
  50.         sort(a , 5000)                                ;
  51.         printf("%4d" , a[0])                          ;
  52.         for(i = 1 ; i < n ; i ++) {
  53.                 if(! (i % 10)) printf("\n%4d" , a[i]) ;
  54.                 else printf(" , %4d" , a[i])          ;
  55.         }
  56.         printf("\n")                                  ;
  57. }
复制代码
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2019-3-18 16:20:39 | 显示全部楼层
jackz007 发表于 2019-3-18 16:17
用 sort() 函数按从大到小排序,然后,取前 n 个即可

        下面是完整测试代码

但是光sort函数的时间复杂度已经不小于O[arr.size*log(arr.size)],因为在前N个之外的数据也一并排序了,执行了冗余的计算
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2019-3-18 16:50:02 | 显示全部楼层
Croper 发表于 2019-3-18 16:20
但是光sort函数的时间复杂度已经不小于O[arr.size*log(arr.size)],因为在前N个之外的数据也一并排序了, ...

这样的话和 冒泡排序 冒泡出前n 个元素后就停止排序,那个效率好点?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2019-3-18 16:52:04 | 显示全部楼层
一道面试题, 我只想到了 冒泡排序 的改造,不知道 这样效率是不是最好的
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2019-3-18 17:06:56 | 显示全部楼层
秋木叶 发表于 2019-3-18 16:50
这样的话和 冒泡排序 冒泡出前n 个元素后就停止排序,那个效率好点?

思路是一样的,但冒泡排序本身就是一种效率比较低的排序。。。如果在长度为M的数组中使用冒泡排序冒N个元素,那么时间复杂度不会低于O[M*N]..
我的思路其实也是只排N个元素,在算法中,这N个元素永远是有序的,在插入新元素时,使用二分查找法。那么插入一个新元素的时间复杂度为O[log(N)],插入M个新元素的时间复杂度为O[M*log(N)],这样效率要高一些。。特别的,当M==N时,时间复杂度为O[N*log(N)],符合一个理想排序算法的平均时间复杂度。
这种排序思路挺常用的。。。但是到底应该叫什么名字。。。把《数据结构与算法》内排序那一章翻完了好像也没找到到底该叫什么。。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2019-3-18 19:21:07 | 显示全部楼层
本帖最后由 jackz007 于 2019-3-18 19:22 编辑
Croper 发表于 2019-3-18 16:20
但是光sort函数的时间复杂度已经不小于O[arr.size*log(arr.size)],因为在前N个之外的数据也一并排序了, ...


        下面这个 sort() 是严格按照要求取数组 array[] 中最大的前 n 个数放到前 n 个元素里,其余部分绝对维持原样。楼主再给测一测看效率如何?
  1. void sort(int array[] , const int m  , const int n)
  2. {
  3.         int c , d , e , i , j                ;
  4.         for(i = 0 ; i < n ; i ++) {
  5.                 c = j = i                    ;
  6.                 d = e = array[i]             ;
  7.                 for(j = i + 1 ; j < m  ; j ++) {
  8.                         if(array[j] > d) {
  9.                                 d = array[j] ;
  10.                                 c = j        ;
  11.                         }
  12.                 }
  13.                 array[i] = d                 ;
  14.                 array[c] = e                 ;
  15.         }
  16. }
复制代码
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2019-3-18 19:36:04 | 显示全部楼层
jackz007 发表于 2019-3-18 19:21
下面这个 sort() 是严格按照要求取数组 array[] 中最大的前 n 个数放到前 n 个元素里,其余部 ...

选择排序只排N个元素嘛
和我之前说的冒泡排序同样的问题,选择排序本身就是效率比较低的,这个算法时间复杂度不会小于O[M*N]..,如果真的要追求效率,那么肯定不能选用原始时间复杂度是O[N^2]的排序方法来改啊
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2019-3-19 15:25:04 From FishC Mobile | 显示全部楼层
我在书上看到过类似的 书上推荐的算法是 选取数组中第n个数作为基数 然后将数组中每个数与选取的基数比较 大的放左边 小的放右边 然后取选取基数的下标 如果大于n 说明最大的前n个数在左边 剔除左边下标减n个最小的数 反之同理 不过需要修改数组而且得到的数是无序的 因为这个算法没有排序过程 书上看到的 《剑指offer》
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2019-3-30 04:43:00 | 显示全部楼层
Croper 发表于 2019-3-18 16:04
时间复杂度O[arr.size*N]空间复杂度O[N]
插入部分改用链表时间复杂度可达到O[arr.size*log(N)],但链表 ...


时间复杂度计算有误,如果使用list,并不能高效地使用二分查找,因此 时间复杂度仍然是O[M*N];

最好的方法应该是建立最大堆
  1. #include <vector>

  2. using namespace std;

  3. class maxheap {
  4. private:
  5.         vector<int> nums;

  6.         int adjustnode(int i) {
  7.                 int maxpos = i;
  8.                 int a = (i+1 << 1) -1;
  9.                 if (a < nums.size() && nums[a]>nums[maxpos]) maxpos = a;
  10.                 if (a+1 < nums.size() && nums[a+1]>nums[maxpos]) maxpos = a+1;
  11.                 if (i != maxpos) {
  12.                         int tmp = nums[maxpos];
  13.                         nums[maxpos] = nums[i];
  14.                         nums[i] = tmp;
  15.                 }
  16.                 return maxpos;
  17.         }
  18. public:
  19.         maxheap(vector<int> input) {
  20.                 nums = input;
  21.                 for (int i = (nums.size() - 1 >> 1) - 1; i >= 0; --i) {
  22.                         adjustnode(i);
  23.                 }
  24.         }

  25.         int pop() {
  26.                 int num = nums[0];
  27.                 nums[0] = nums.back();
  28.                 nums.pop_back();

  29.                 int n = 0;
  30.                 int m;
  31.                 while (n != (m = adjustnode(n))) n = m;

  32.                 return num;
  33.         }
  34. };


  35. vector<int> maxN(vector<int> nums, int N) {
  36.         maxheap h(nums);
  37.         vector<int> ret;
  38.         for (int i = 0; i < N; ++i)
  39.                 ret.push_back(h.pop());
  40.         return ret;
  41. }
复制代码

时间复杂度O[N*log(M)]
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-4-26 11:19

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表