好长,好复杂。。
排序算法
第一类
O(n2)
O
(
n
2
)
算法:选择、插入、冒泡
第二类
O(nlogn)
O
(
n
l
o
g
n
)
算法:堆排、归并、快排
第三类玄学算法:计数、基数、桶排
然而我并没有仔细学过。。所以就先从最基础的地方开始。
- 选择排序:每次从序列中选一个最小的放在最前面,重复执行。
- 插入排序:假设前k个已经排好序,我们就可以找到新的数插进去。如果用二分查找仍然是 O(n2) O ( n 2 ) 的,因为找到之后移动数组是 O(n) O ( n ) 的。
- 希尔排序:插入排序的一个变种。希尔排序的执行过程是这样的:
对于一个序列,我们首先选取相隔k个的一组数。例如, n=10,k=5 n = 10 , k = 5 ,我们就选出来 [1,6],[2,7],[3,8],[4,9],[5,10] [ 1 , 6 ] , [ 2 , 7 ] , [ 3 , 8 ] , [ 4 , 9 ] , [ 5 , 10 ] 这些数
然后对每一组元素分别进行插入排序,合并起来。
下一次,我们就选取 k=2 k = 2 ,然后对 [1,3,5,7,9] [ 1 , 3 , 5 , 7 , 9 ] 和 [2,4,6,8,10] [ 2 , 4 , 6 , 8 , 10 ] 进行插入排序再合并。以此类推,当最终 k=1 k = 1 的时候,进行的插入排序工作量会大大减少。我们将k称为增量,如果k像这样倍减其复杂度仍然是 O(n2) O ( n 2 ) 。
事实上,增量的选取对希尔排序的复杂度有着重要影响。一种常见的选取是Hibbard增量, an=2n−1 a n = 2 n − 1 ,其时间复杂度是 O(nn−−√) O ( n n ) 的。 - 冒泡排序:重复访问数组,遇到相反元素就交换直到未有能交换者。
- 计数排序:值域内的排序,开一个数组维护某个值的数量,然后扫一遍数组即可,复杂度 O(n+m) O ( n + m ) ,其中m是值域。
- 基数排序:类似建一张hash表。我们以个位为基准放桶里,然后对每个桶取出来元素以十位为单位放到桶里。。。这样递归下去即可。分成两种,一种是MSD,一种是LSD。LSD的复杂度是 O(d(n+r)) O ( d ( n + r ) ) ,d为位数,r为基数。
- 桶排序:假定将值域为
m
m
,将数据分布在个桶中,然后对桶进行排序,如果选择插入排序复杂度是
Θ(n+n2k)
Θ
(
n
+
n
2
k
)
,前提是数据均匀随机分布。当
k=n
k
=
n
时复杂度为
O(n)
O
(
n
)
,k增大会使得算法效率发生显著改变,当
k=n
k
=
n
时退化为计数排序。
事实上,如果我们进行一些总结,可以发现计数排序是桶排序对k进行选择的一种情况,而如果对桶中的数据递归调用桶排序过程,那么这个排序就是基数排序。 - 二叉排序树排序:插到二叉排序树即可。平均 O(nlogn) O ( n l o g n ) ,但可能退化到 O(n2) O ( n 2 ) 。也可以用替罪羊树、treap等平衡树使之稳定到 O(nlogn) O ( n l o g n ) ,不过会增加时间开销。
- 堆排序:加入一个堆中,然后不断删除元素并维护堆的性质,复杂度
O(nlogn)
O
(
n
l
o
g
n
)
。
推荐:https://www.cnblogs.com/chenweichu/articles/5710567.html
http://www.cnblogs.com/chenweichu/articles/5710635.html - 分治排序:个人认为最优雅的排序算法,没有之一。对数列进行分治,然后对子数列排序,最后再合并。复杂度 O(nlogn) O ( n l o g n ) ,实现参见之后的逆序对。
- 快速排序:选取一个数,然后将比它大的放在前面,否则放在后面,对此过程进行递归处理即可。选取的数可以随机一下。
离散化
这里给一种比较神奇的黑科技。。
for(int i = 1; i <= n; ++i) b[i]=a[i];
sort(b+1,b+n+1);
int un=unique(b+1,b+n+1)-b-1;
for(int i=1;i<=n;++i) a[i]=lower_bound(b+1,b+un+1,a[i])-b;
cf670C
懒所以开了个map,发现用map离散化瞎搞一搞就好了的样子。。
#include <iostream>
#include <cstdio>
#include <map>
using namespace std;
#define N 200003
int n, t, cnt;
int aud[N];
int ansy, anss, arr;
struct node {
int voice, sub;
}movie[N];
map<int, int> m;
int main() {
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
cin>>n;
for(int i = 1; i <= n; ++i) cin>>aud[i];
cin>>t;
for(int i = 1; i <= t; ++i) cin>>movie[i].voice;
for(int i = 1; i <= t; ++i) cin>>movie[i].sub;
for(int i = 1; i <= n; ++i)
if(!m.count(aud[i]))
m.insert(make_pair(aud[i], 1));
else ++m[aud[i]];
for(int i = 1; i <= t; ++i) {
if(!m.count(movie[i].voice)) {
if(ansy == 0)
ansy = 0,
anss = (m.count(movie[i].sub) ? m[movie[i].sub] : 0), arr = i;
}
else {
if(m[movie[i].voice] > ansy)
ansy = m[movie[i].voice],
anss = (m.count(movie[i].sub) ? m[movie[i].sub] : 0),
arr = i;
if(m[movie[i].voice] == ansy && m.count(movie[i].sub) && m[movie[i].sub] > anss)
anss = m[movie[i].sub], arr = i;
}
}
cout<<arr<<endl;
}
是不是非常sabi。。用时24秒。。
然后就看了一下楼下大佬的,发觉有这样一种操作:如果用upper_bound减去lower_bound就可以得出值了..好有道理诶
参考资料
https://baike.baidu.com/item/%E5%B8%8C%E5%B0%94%E6%8E%92%E5%BA%8F/3229428?fr=aladdin
https://www.cnblogs.com/chengxiao/p/6104371.html
http://blog.csdn.net/foliciatarier/article/details/53891144
https://www.cnblogs.com/dwj411024/p/5978821.html
http://blog.csdn.net/cauchyweierstrass/article/details/49919559
https://www.cnblogs.com/jingmoxukong/p/4311237.html