同时找到最大值与最小值

找到n个元素中的最大/小值,比较次数为n-1, 找到n个元素中的最大值和最小值,可以Two Pass,比较次数为2n-2

也可以One Pass,比较次数至多为\(\left \lfloor 3n/2 \right \rfloor\)

首先对最大值和最小值进行初始化,n为奇数时MAX和MIN均初始化v[0],n为偶数时MAX和MIN分别初始化为v[0]和v[1]中的最大值和最小值

然后每两个数比较一次,小的数和MIN比较,大的数和MAX比较,共进行三次

  • 对于n为奇数,总比较次数为\(3(n-1)/2 = \left \lfloor 3n/2 \right \rfloor\)
  • 对于n为偶数,总比较次数为\(3(n-2)/2 + 1= 3n/2 - 2\)

无论哪种情况,总的比较次数至多为\(\left \lfloor 3n/2 \right \rfloor\)

#include <iostream>
#include <vector>
using namespace std; void findMaxMin(vector<int>& v){ int n = v.size();
if(n == 0) return; int MIN, MAX, i;
if(n % 2 == 0){
if(v[0] > v[1]) {
MIN = v[1];
MAX = v[0];
} else {
MIN = v[1];
MAX = v[0];
}
i = 2;
} else {
i = 1;
MIN = MAX = v[0];
} while(i < n){
if(v[i] < v[i+1]){
MIN = min(v[i], MIN);
MAX = max(v[i+1], MAX);
} else {
MIN = min(v[i+1], MIN);
MAX = max(v[i], MAX);
}
i += 2;
} cout << "MAX = " << MAX << ", MIN = " << MIN << endl;
}
int main(){
vector<int> v{1,4,3,2,5,6,0,9,6,8,8,9}; findMaxMin(v);
return 0;
}

O(n)最坏时间复杂度找到第k大算法(BFPRT)

BFPRT算法可以在O(n)最坏时间复杂度找到第k大,也可用于解决TOP-K问题

215. Kth Largest Element in an Array

随机化使用均摊的思想就不写了,用BFPRT检验下

严格的BFPRT

class Solution {
public: void InsertSort(vector<int>& a, int l, int r){
for(int i = l + 1; i <= r; i++){
auto x = a[i];
auto j = i;
while(j > l && x < a[j-1]){
a[j] = a[j-1];
j--;
}
a[j] = x;
} } int Partiton(vector<int>& a, int l, int r, int m){
int x = a[m];
int i = l;
int j = r; swap(a[m], a[l]);
while(i < j){
while(i < j && a[j] >= x) j--;
a[i] = a[j];
while(i < j && a[i] <= x) i++;
a[j] = a[i];
}
a[i] = x;
return i;
} int BFPRT(vector<int>& a, int l, int r, int k){
if(r - l + 1 < 5) {
InsertSort(a, l, r);
return l + k - 1;
} int e = l - 1; for(int i = l; i + 4 <= r; i += 5){
InsertSort(a, i, i+4);
swap(a[++e], a[i+2]);
} int m = BFPRT(a, l, e, (e - l + 1) / 2 + 1);
int p = Partiton(a, l, r, m);
int n = p - l + 1;
if(n == k) return p;
if(n > k) return BFPRT(a, l, p-1, k);
return BFPRT(a, p+1, r, k - n);
} int findKthLargest(vector<int>& nums, int k) { return nums[BFPRT(nums, 0, nums.size()-1, nums.size() - k + 1)];
}
};

我自己最开始的写法,对找中位数的BFPRT函数做了特殊处理,使用FindMin代替,减少了无必要的BFPRT递归调用

class Solution {
public: int InsertSort(vector<int>& a, int l, int r){
for(int i = l + 1; i <= r; i++){
auto x = a[i];
auto j = i;
while(j > l && x < a[j-1]){
a[j] = a[j-1];
j--;
}
a[j] = x;
}
return l + (r - l) / 2;
} int Partiton(vector<int>& a, int l, int r, int m){
int x = a[m];
int i = l;
int j = r; swap(a[m], a[l]);
while(i < j){
while(i < j && a[j] >= x) j--;
a[i] = a[j];
while(i < j && a[i] <= x) i++;
a[j] = a[i];
}
a[i] = x;
return i;
} int FindMid(vector<int>& a, int l, int r){
if(r - l + 1 < 5) return InsertSort(a, l, r);
int p = l - 1; for(int i = l; i < r - 5; i += 5){
int mid = InsertSort(a, i, i+4); swap(a[++p], a[mid]);
}
return FindMid(a, l, p);
} int BFPRT(vector<int>& a, int l, int r, int k){
if(l == r) return a[l]; int m = FindMid(a, l, r);
int p = Partiton(a, l, r, m);
int n = p - l + 1;
if(n == k) return a[p];
if(n > k) return BFPRT(a, l, p, k);
return BFPRT(a, p+1, r, k - n);
} int findKthLargest(vector<int>& nums, int k) {
return BFPRT(nums, 0, nums.size()-1, nums.size() - k + 1);
}
};

算法分析

当找到中位数的中位数时,除了不能被n整除的剩余组和包含有x的那个组除外,至少有一半的组中每个组至少3个元素大于x,所以大于x的元素个数最少为

\[\begin{aligned}
3 \left \lceil \frac{1}{2}\left \lceil \frac{n}{5}\right \rceil{} -2 \right \rceil \geq \frac{3n}{10} - 6
\end{aligned}
\]

递归选第k大最多有\(7n/ 10 + 6\)个元素

最坏情况下\(T(n) \leq T(\left \lceil n/5 \right \rceil) + T(7n/ 10 + 6) + O(n)\)

假定\(T(n) \leq cn\) 且\(O(n)\)的上界为\(an\)

\[\begin{aligned}
T(n) &\leq c\left \lceil n/ 5 \right \rceil + c(7n/ 10 + 6) + an\\
&\leq cn/5 + c + 7cn/10 + 6c + an \\
& = 9cn / 10 + 7c + an \\
& = cn + (-cn/10) + 7c + an
\end{aligned}
\]

只要使得\(-cn/10 + 7c + an \leq 0\)即可, 也就是$c \geq 10a(n / n - 70) $ 假设n>140,则\((n / n - 70) \leq 2\), 选择\(c \geq 20a\)即可

问题

  • 如果每组分为3个元素,BFPRT的运行时间是线性的吗?不是(\(T(n) \leq T(\left \lceil n/ 3 \right \rceil) + T(2n/3 + 4)\),由此得到常数项a,c为0时才满足线性时间,不符合)
  • 每组分为7个呢?是

参考

TODO

k分位数

BFPRT: O(n)最坏时间复杂度找第K大问题的更多相关文章

  1. 找第k大数,最坏时间复杂度O(n)

    (转载请注明出处,http://www.cnblogs.com/fangpei/p/3538331.html ) 以前写过的一篇,搬过来. 上算法课的时候听到老师讲这个问题,觉得还是蛮有意思的.已知数 ...

  2. 17082 两个有序数序列中找第k小

    17082 两个有序数序列中找第k小 时间限制:1000MS  内存限制:65535K 提交次数:0 通过次数:0 题型: 编程题   语言: 无限制 Description 已知两个已经排好序(非减 ...

  3. 算法打基础——顺序统计(找第k小数)

    这次主要是讲如何在线性时间下找n个元素的未排序序列中第k小的数.当然如果\(k=1 or k=n\),即找最大最小 数,线性时间内遍历即可完成,当拓展到一般,如中位数时,相关算法就值得研究了.这里还要 ...

  4. 17082 两个有序数序列中找第k小(优先做)

    17082 两个有序数序列中找第k小(优先做) 时间限制:1000MS  内存限制:65535K提交次数:0 通过次数:0 题型: 编程题   语言: G++;GCC;VC Description 已 ...

  5. 17082 两个有序数序列中找第k小(优先做) O(logn)

    17082 两个有序数序列中找第k小(优先做) 时间限制:1000MS  内存限制:65535K提交次数:0 通过次数:0 题型: 编程题   语言: G++;GCC;VC Description 已 ...

  6. luogu_P1177 【模板】快速排序 (快排和找第k大的数)

    [算法] 选取pivot,然后每趟快排用双指针扫描(l,r)区间,交换左指针大于pivot的元素和右指针小于pivot的元素,将区间分成大于pivot和小于pivot的 [注意] 时间复杂度取决于pi ...

  7. 找第k大的数

    (找第k大的数) 给定一个长度为1,000,000的无序正整数序列,以及另一个数n(1<=n<=1000000),接下来以类似快速排序的方法找到序列中第n大的数(关于第n大的数:例如序列{ ...

  8. [LeetCode] Find K-th Smallest Pair Distance 找第K小的数对儿距离

    Given an integer array, return the k-th smallest distance among all the pairs. The distance of a pai ...

  9. cogs930找第k小的数(k-th number)

    cogs930找第k小的数(k-th number) 原题链接 题解 好题... 终极版是bzoj3065(然而并不会) 先讲这个题... 维护\(n+1\)个值域线段树(用主席树),标号\(0\) ...

随机推荐

  1. JavaEE-实验一 Java常用工具类编程

    该博客仅专为我的小伙伴提供参考而附加,没空加上代码具体解析,望各位谅解 1.  使用类String类的分割split 将字符串  “Solutions to selected exercises ca ...

  2. 十八:jinja2之include标签

    用于将页面的某一块地方抽取出来,要嵌入内容的时候使用,继承的概念 把具体内容分别放到其他地方同一管理,要用的时候使用include继承 使用include的时候可以直接使用接收的数据

  3. 模糊查询基于select遍历json文件自动填充的实现

    HTML页面 <tr> <td align="left"><span>案由</span> <input type=" ...

  4. 将JSON字符串反序列化为指定的.NET对象类型

    目录导航: 前言: 方法一.在项目中定义对应的对象参数模型,用于映射反序列化出来的参数(复杂JSON字符串数据推荐使用): 方法二.直接将JSON字符串格式数据反序列化转化为字典数据(简单JSON字符 ...

  5. Java编程思想—八皇后问题(数组法、堆栈法)

    Java编程思想-八皇后问题(数组法.堆栈法) 实验题目:回溯法实验(八皇后问题) 实验目的: 实验要求: 实验内容: (1)问题描述 (2)实验步骤: 数组法: 堆栈法: 算法伪代码: 实验结果: ...

  6. centos7 系統vps安裝mysql5.6及設置本地遠程連接筆記

    用xshell連接上vps 1,下载mysql的repo源 wget http://repo.mysql.com/mysql-community-release-el7-5.noarch.rpm su ...

  7. LoadRunner对sockets报文进行压力测试(脚本设计)

    1. LR新建一个windows sockets项目 2. action中写入测试代码 如: #include "lrs.h" Action() { char *recvbuf; ...

  8. Linux (1)

    @https://blog.csdn.net/mayi_xiaochaun这人博客里有一系列linux教程 @linux中,文件名最前加/  比如 cd /usr/local是绝对路径 若#前显示当前 ...

  9. 【miscellaneous】星光级超低照度摄像机技术分析

    低照度摄像机采用了超灵敏度图像传感器和独有的电子倍增和噪点控制技术能够极大地提高摄像机的灵敏度,并且具备24小时全彩色实时效果,绝无普通低照度摄像机出现的拖尾现象,以满足对夜间高品质监控的需求.    ...

  10. idea 如何运行maven项目

    1:run→Edit configurations 2:配置tomcat,左边如果没有tomcat server的话,点击 “+”,选择tomcat  server→local,在右边server选项 ...