Description

给定线性序集中n个元素和一个整数k,n<=2000000,1<=k<=n,要求找出这n个元素中第k小的数。

Input

第一行有两个正整数n,k. 接下来是n个整数(0<=ai<=1e9)。

Output

输出第k小的数

Sample Input

6 3
1 3 5 2 4 6

Sample Output

3

利用快速排序可以找出第k小的,加上随机函数改进一下:

#include <cstdio>
#include <cstdlib>
#include <ctime>
#include <iostream> int num[2000001]; void quictSort(int, int, int);
int partition(int, int); int main()
{
int n, m, i;
srand(unsigned(time(NULL))); // 随机函数种子
while (~scanf("%d%d", &n, &m))
{
for (i = 0; i < n; i++)
scanf("%d", &num[i]); quictSort(0, n - 1, m - 1); printf("%d\n", num[m - 1]);
}
return 0;
}
// 快速排序
void quictSort(int left, int right, int mTop)
{
if (left < right)
{
int p = partition(left, right); // 分为两段 if (p == mTop) // 如果随机找到第mTop小就直接返回
return;
if (p < mTop)
quictSort(p + 1, right, mTop); // 找到的位置比mTop小就在[p + 1, right]区间找
if (p > mTop)
quictSort(left, p - 1, mTop); // 找到的位置比mTop大就在[left, p - 1]区间找
}
}
// 从小到大排
int partition(int left, int right)
{
int r = rand() % (right - left + 1) + left; // 随机选择一个数
int key = num[r];
std::swap(num[r], num[left]); // 交换到数组首位
while (left < right)
{// 从数组后面开始, 找比随机选择的数小的, 然后从前找比随机选择的数大的
while (left < right && num[right] >= key)
right--;
if (left < right)
num[left] = num[right]; while (left < right && num[left] <= key)
left++;
if (left < right)
num[right] = num[left];
}
num[left] = key; // 将随机选择的数存回
return left; // 返回随机选择的数分割数组的下标, 左边都是比它小的, 右边都是比它大的
}

中位数法线性时间选择划分:

AC代码:

#include <cstdio>
#include <cstdlib> int num[2000001]; int select(int low, int high, int top);
int partition(int low, int high, int median);
void selectSort(int low, int high);
void swap(int &a, int &b); int main()
{
int n, m, i; while (~scanf("%d%d", &n, &m))
{
for (i = 0; i < n; i++)
scanf("%d", &num[i]); printf("%d\n", select(0, n - 1, m - 1)); /*
for (i = 0; i < n; i++)
printf("%d%c", num[i], i < n - 1 ? ' ' : '\n');
*/
}
return 0;
}
// 中位数法线性时间选择
int select(int low, int high, int top)
{
// 小于75个数据随便用一个排序方法
if (high - low < 74)
{
selectSort(low, high); // 选择排序
return num[low + top]; // 排完序直接返回第low + top的数
} int groupNum = (high - low - 4) / 5; // 每组5个数, 计算多少个组, 从0开始计数 for (int i = 0; i <= groupNum; i++)
{
int start = low + 5 * i; // 每组的起始位置
int end = start + 4; // 每组的结束位置
for (int j = 0; j < 3; j++) // 从小到大冒3个泡
for (int k = start; k < end - j; k++)
if (num[k] > num[k + 1])
swap(num[k], num[k+1]);
swap(num[low + i], num[start + 2]); // 每组的中位数交换到前面第low + i的位置
}
// 上面排完后, 数组low + 0 到 low + groupNum都是每一组的中位数
int median = select(low, low + groupNum, (groupNum + 1) / 2); // 找中位数的中位数
int p = partition(low, high, median); // 将数组分为两段, 左边的小于中位数的中位数, 右边的大于中位数的中位数
int n = p - low; // 计算p到low之间有多少个数, 后面得减掉 if (n == top)
return num[p]; // 如果运气好, 刚好要找的就是中位数
if (n > top)
return select(low, p - 1, top); // n比top大就在左边找
if (n < top)
return select(p + 1, high, top - n - 1); // n比top小就在右边找, 并且top要减去已经大的个数
}
// 以中位数进行分割, 分成两半
int partition(int low, int high, int median)
{
int p;
for (int i = low; i <= high; i++)
if (num[i] == median)
{
p = i;
break;
}
// 将中位数交换到最前面
swap(num[p], num[low]);
// 记下最前面的数
int key = num[low];
// 把小于key的放前面, 大于key的放后面
while (low < high)
{
while (num[high] >= key && low < high)
high--;
if (low < high)
num[low] = num[high];
while (num[low] <= key && low < high)
low++;
if (low < high)
num[high] = num[low];
}
// 分别从两头开始, 找到中间时, 把key存回
num[low] = key;
return low;
}
// 选择排序
void selectSort(int low, int high)
{
for (int i = low; i <= high; i++)
{
int MIN = i;
for (int j = i + 1; j <= high; j++)
if (num[MIN] > num[j])
MIN = j;
swap(num[i], num[MIN]);
}
}
// 交换两个元素
void swap(int &a, int &b)
{
int temp = a;
a = b;
b = temp;
}

算法:线性时间选择(C/C++)的更多相关文章

  1. [图解算法]线性时间选择Linear Select——<递归与分治策略>

    #include <ctime> #include <iostream> using namespace std; template <class Type> vo ...

  2. 【Unsolved】线性时间选择算法的复杂度证明

    线性时间选择算法中,最坏情况仍然可以保持O(n). 原因是通过对中位数的中位数的寻找,保证每次分组后,任意一组包含元素的数量不会大于某个值. 普通的Partition最坏情况下,每次只能排除一个元素, ...

  3. 算法线性编程珠玑读书笔记之----->使用线性算法求解连续子序列的最大和

    这段时间笔者几篇文章介绍了改算法线性的文章. 关联文章的地址 这个算法我在我的博客里应用动态规划做过,详细实现请参阅我的dp板块,下面给出书上最快的算法,时间复杂度为O(n),称之为线性算法. #in ...

  4. Top k问题(线性时间选择算法)

    问题描述:给定n个整数,求其中第k小的数. 分析:显然,对所有的数据进行排序,即很容易找到第k小的数.但是排序的时间复杂度较高,很难达到线性时间,哈希排序可以实现,但是需要另外的辅助空间. 这里我提供 ...

  5. C++分治策略实现线性时间选择

    问题描述: 给定线性序集中n个元素和一个整数k,1≤k≤n,要求找出这n个元素中第k小的元素,即如果将这n个元素依其线性序排列时,排在第k个的元素即为要找到元素. 细节须知:(与之前的随笔相比) (1 ...

  6. 关于曲线 规划 算法 线性 S曲线 贝塞尔曲线

    工控领域经常会涉及速度加减速的算法:线性加减速,S曲线加减速(sin函数,拓展其他三角函数曲线), 贝塞尔曲线,等等. 线性加减速:    设定起始速度V0,目标速度V1,加速时间Ta(s,或加速度) ...

  7. 查找第K小的元素(利用中位数线性时间选择)(C)

    找任意第k个小的元素 #include <stdio.h> #include <stdlib.h> #include <ctime> #include <io ...

  8. 剑指Offer——分治算法

    剑指Offer--分治算法 基本概念 在计算机科学中,分治法是一种很重要的算法.字面上的解释是"分而治之",就是把一个复杂的问题分成两个或更多的相同或相似的子问题,再把子问题分成更 ...

  9. K:找寻数组中第n大的数组元素的三个算法

    相关介绍:  给定一个数组,找出该数组中第n大的元素的值.其中,1<=n<=length.例如,给定一个数组A={2,3,6,5,7,9,8,1,4},当n=1时,返回9.解决该问题的算法 ...

随机推荐

  1. linux时间校准 设置时间为上海时区

      [root@localhost log]# rm -f /etc/localtime [root@localhost log]# cp /usr/share/zoneinfo/Asia/Shang ...

  2. 分布式协调服务之Zookeeper集群部署

    一.分布式系统概念 在聊Zookeeper之前,我们先来聊聊什么是分布式系统:所谓分布式系统就是一个系统的软件或硬件组件分布在网络中的不同计算机之上,彼此间通过消息传递进行通信和协作的系统:简单讲就是 ...

  3. 懒人福音——GitHub 热点速览 Vol.42

    作者:HelloGitHub-小鱼干 懒人福音是什么?就是省时省事,正如 Waypoint 一样,你不需要在多个平台构建代码即可部署发布应用,它允许你将应用程序构建.部署和发布生命周期定义为代码.Bi ...

  4. Helium文档10-WebUI自动化-Text识别网页上的任何文本或标签

    前言 Text关键字的作用是识别网页上的文字,在一般UI查找中使用率非常高,但是需要注意,如果网页上有相同的文字,那么只能识别到第一个 入参介绍 以下是Text的源码 有5个如参:后面4个参数是上下左 ...

  5. Java 等待/通知机制

    等待/通知的目的是确保等待线程从wait()方法返回时能够感知到通知线程对变量所做出的的修改: 等待方遵循如下原则: 1.获取对象的锁 2.如果条件不满足,那么调用对象的wait()方法,被通知后任要 ...

  6. Qt中的Q_OBJECT作用, 以及信号槽

    自定义类时, 如果需要使用Qt框架提供的信号槽机制, 必须满足以下两个条件: 第一:该类必须是QObject类的子类或者间接子类. 其次:在定义类时, 首行必须加上宏Q_OBJECT class My ...

  7. this()与super()

    1. 构造器中第一行默认是super(),一旦直接父类的构造器中没有无参的,那么必须显式调用父类的某个有参构造. 2. 构造器中第一行的super()可以换成this(),但是this()和super ...

  8. Stream(一)

    public class Test06 { /* * StreamAPI: * StreamAPI是用来处理数据,处理集合等容器中的数据,处理操作有:查询.筛选.删除.过滤.统计.映射等. * 希望能 ...

  9. python机器学习卷积神经网络(CNN)

    卷积神经网络(CNN) 关注公众号"轻松学编程"了解更多. 一.简介 ​ 卷积神经网络(Convolutional Neural Network,CNN)是一种前馈神经网络,它的人 ...

  10. 《Clojure编程》笔记 第2章 函数式编程

    目录 背景简述 第2章 函数式编程 背景简述 本人是一个自学一年Java的小菜鸡,理论上跟大多数新手的水平差不多,但我入职的新公司是要求转Clojure语言的.坊间传闻:通常情况下,最好是有一定Jav ...