zoukankan      html  css  js  c++  java
  • 求第k小数

    这篇文章包括题目思路代码时间复杂度分析几部分。

    题目:洛谷 求第k小的数

    这里的k可以取0,也就是有第0小的数(最小的数),所以,实际上相当于平常说的求第k+1小的数

    想到了几种做法,

    首先,排序,输出num[k];

    其次,用一个辅助数组保存前(k+1)个最小的数,遍历原数组的时候更新辅助数组(可以遍历或者大根堆),最后输出这个辅助数组中的最大值;

    然后,还可以用快速排序的二分思想,将数组分成小于基准的数、基准、大于基准的数共三部分,比较k和基准的序号,相等输出基准值,小于递归基准左侧的部分,大于递归基准右侧的部分,相当于二分查找和快速排序的结合。

    下面是第二种和第三种的代码

    //方法二
    #include <stdio.h>
    #define MAXSIZE 5000000
    
    long long num[MAXSIZE];//辅助数组,存储已遍历的前k+1小的数
    
    
    int main()
    {
        long long n, k,tmp;
        long long max = 0, max_node = 0, top = -1;
    
        scanf("%lld", &n);
        scanf("%lld", &k);
        for (long long i = 0; i < n; i++)
        {
            scanf("%lld", &tmp);
            if (top < k)//开始时,辅助数组元素个数小于k+1,直接加入
            {
                num[++top] = tmp;
                if (max < tmp)//记录好辅助数组的最大值和最大值的序号
                {
                    max = tmp;
                    max_node = top;
                }
            }
            else//当辅助数组加入了k+1个元素之后
            {
                if (max > tmp)//如果tmp小于辅助数组当前的最大值
                {
                    max = tmp;
                    num[max_node] = tmp;//将最大值元素替换为tmp
                    for (long long i = 0; i <= top; i++)//遍历辅助数组,重新选取最大值和最大值结点
                        if (max < num[i])
                        {
                            max = num[i];
                            max_node = i;
                        }
                }
            }
        }
        printf("%lld", max);
        return 0;
    }
    //方法三
    #include <stdio.h> #define MAXSIZE 5000000 long long num[MAXSIZE]; long long n, k; void sort(long long left, long long right) { if (left > right) return; long long greater = left, less = right, std = num[left]; while (greater < less) { while (less > greater&&num[less] >= std) less--; while (greater < less&&num[greater] <= std) greater++; if (greater != less) { long long tmp = num[less]; num[less] = num[greater]; num[greater] = tmp; } else { long long tmp = num[less]; num[less] = num[left]; num[left] = tmp; } } if (less == k)//原本的两部分都要递归变成了只递归一部分 printf("%lld", num[less]); else if (less > k) sort(left, less - 1); else sort(less + 1, right); } int main() { scanf("%lld", &n); scanf("%lld", &k); for (long long i = 0; i < n; i++) scanf("%lld", &num[i]); sort(0, n - 1); return 0; }

    时间复杂度分析

    第一种,时间复杂度为O(n*log n),太大

    第二种,时间复杂度为O(n~k*n),这种方法的最好和最坏的时间复杂度相差很大,最好的情况是原数组升序排列,时间复杂度为n,最坏的情况是原数组降序排列,时间复杂度为kn,当k≈n时,更是达到n2的级别,

    第三种,时间复杂度为Θ(n),写出递推方程T(n)=T(n/2)+O(n),利用主定理可以求解,而且最好和最坏时间复杂度都是Θ(n)

    最后的结果是第一种60分,第二种0分、开 O2 40分,第三种100分(开O2更慢)

    可能是测试样例太刁钻,导致第二种成绩这么差吧,唉~

     第二种,如果把辅助数组当做大根堆,每次更新堆而不是遍历数组,那么时间复杂度是O(n*log k)

  • 相关阅读:
    pywin32解析office文档
    解决NGUI自动被设置LYAER
    ngui的tween的tweenFactor属性
    ngui中 代码调用按钮事件(后来改成了按钮绑定键盘..)
    unity调用摄像头的方法
    坐标转换,这次是反过来,屏幕坐标转换成世界坐标
    unity5.3 安卓广告插件打包出错的理解
    从世界坐标转换成ui的rect坐标的方法
    关于unity碰撞检测器的用法
    测试第一篇标题
  • 原文地址:https://www.cnblogs.com/lylhome/p/13300320.html
Copyright © 2011-2022 走看看