冒泡和选择排序就不放了,挺简单的
快排和归并排序都是排序的优化算法
快速排序
快排平均时间复杂的是O(nlogn)
空间复杂度最好是O(nlogn),最差退化为冒泡排序O(n)
void quick_sort(int q[], int l, int r){
if(l > r) return;
int i = l, j = r, x = q[(int)((l + r) / 2)]; //i,j分别指向数组首尾,x取中间元素值
while(i < j){
while (q[i] < x) i ++;
while (q[j] > x) j --;
if(i < j) swap(q[i], q[j]);
}
quick_sort(q, l, j - 1);
quick_sort(q, j + 1, r);
}
归并
归并的时间复杂度都是O(nlogn)
空间复杂度是O(n)
但归并排序的稳定性是比快排要好的
比如一个数组 2(A) 4(B) 2© 9(D) 4(E) (括号里为输入顺序标识)
归并排序之后会2(A) 2© 4(B) 4(E) 9(D)
不会乱序
void merge_sort(int arr[], int l, int r)
{
if(l >= r) return;
int mid = (l + r) / 2;
merge_sort(arr, l, mid);
merge_sort(arr, mid + 1, r);
int tmp[r - l + 1];
int i = l, j = mid + 1, k = 0;
while(i <= mid && j <= r)
if(arr[i] < arr[j]) tmp[k ++] = arr[i ++];
else tmp[k ++] = arr[j ++];
while(i <= mid) tmp[k ++] = arr[i ++];
while(j <= r) tmp[k ++] = arr[j ++];
for(i = l; i <= r; i ++)
arr[i] = tmp[i - l];
}
求部分和
用于求数组子区间和的方法,如果是多次输入求多个区间,数据规模较大时便会可能超时
所以用一个新数组保留前n项和就可以把时间复杂度降为O(n)
#include<iostream>
using namespace std;
#define L long
L a[100010], sum[100010];
int main(){
L n, m;
cin>>n>>m;
for(L i = 1; i <= n; i ++){
cin>>a[i];
sum[i] = sum[i - 1] + a[i]; //保存前n项和
}
for(L i = 1; i <= m; i ++){
L l, r;
cin>>l>>r;
cout<<sum[r] - sum[l - 1]<<endl; //a[l]+……+a[r] = sum[r] – sum[l-1]
}
}
差分法
不太好解释,放一道例题助理解吧
一个长度为n的整数序列。
对其进行m次操作,每个操作包含三个整数l, r, c,表示将序列中[l, r]之间的每个数加上c。
请你输出进行完所有操作后的序列。
输入格式
第一行包含两个整数n和m。
第二行包含n个整数,表示整数序列。
接下来m行,每行包含三个整数l,r,c,表示一个操作。
输出格式
共一行,包含n个整数,表示最终序列。
数据范围
1≤n,m≤100000,
1≤l≤r≤n,
−1000≤c≤1000,
−1000≤整数序列中元素的值≤1000
如果用暴力做法每次都循环一遍区间的值然后操作的话时间肯定会超限
所以用一种巧妙地方法就是构造差分数组,
对区间[l,r]进行+c操作时只需要在差分数组里对b[l] += c,b[r+1] -= c
然后累和恢复数组时就可对区间内所有数+c
代码如下:
#include<iostream>
using namespace std;
int a[100010], b[100010];
int main(){
int n, m;
cin>>n>>m;
for(int i = 1; i <= n; i ++){
cin>>a[i];
b[i] = a[i] - a[i - 1]; //构造差分数组
}
while(m --){
int l, r, c;
cin>>l>>r>>c;
b[l] += c;
b[r + 1] -= c;
}
for(int i = 1; i <= n; i ++){
b[i] = b[i] + b[i - 1];
cout<<b[i]<<" ";
}
return 0;
}