目录
1、快速排序
核心思想:先找基准数,然后从左找第一个比它大的数,从右找第一个比他小的数,然后交换这两个数,再接着找,直到二者相遇,此时,交换基准数与相遇点,这时基准数归位。然后递归左右两边,最后全部归位。每一轮下来,基准数会归位到最终排序的相应位置。平均时间复杂度为nlogn。
小tick:CPU中位运算的速度比除法快。
示例代码:
void quick_sort(int a[], int l, int h){
if(l >= h) return;
int i = l - 1; int j = h + 1; int x = a[l + h >> 1];
while(i < j){
do i ++; while(a[i] < x);
do j --; while(a[j] > x);
if(i < j) swap(a[i], a[j]);
}
quick_sort(a, l, j);quick_sort(a, j + 1, h);
}
2、归并排序
1、核心思想:
取中点,分割为两部分,分别比较。但要记住从最下层开始比较到最上层。
2、代码:
void merge_sort(int q[], int l, int r)
{
if (l >= r) return;
int mid = l + r >> 1;
merge_sort(q, l, mid);
merge_sort(q, mid + 1, r);
int k = 0, i = l, j = mid + 1;
while (i <= mid && j <= r)
if (q[i] <= q[j]) tmp[k ++ ] = q[i ++ ];
else tmp[k ++ ] = q[j ++ ];
while (i <= mid) tmp[k ++ ] = q[i ++ ];
while (j <= r) tmp[k ++ ] = q[j ++ ];
for (i = l, j = 0; i <= r; i ++, j ++ ) q[i] = tmp[j];
}
3、求逆序对
逆序对定义:如果 i < j, 并且 a[i] > a[j],则称此为一个逆序对。暴力求法将会超时!
正解:归并排序 + 当我们发现填充第二个数组中的数,加入备用数组的使用,都要统计mid−i+1,因为此时此刻,我们第一个数组中剩余的所有数,都会和它构成逆序对.
代码:只需要在归并排序 else后面多加一行: res += mid - i + 1
4、整数的二分查找
1、查找等于目标数的第一个数的坐标:
int bsercho(int l, int h, int k){ //k为目标数
while(l < h){
int mid = l + h >> 1; //下整 往左走
if(a[mid] < k) l = mid + 1;
else h = mid; //目标数小于等于数组数时,往左走,要包括mid
}
return l;
}
2、查找等于目标数的最后一个数的坐标:
int bsercht(int l, int h, int k){
while(l < h){
int mid = l + h + 1 >> 1; //上整,往右走
if(a[mid] <= k) l = mid ; //目标数大于等于数组数时,往右走,要包括mid
else h = mid - 1;
}
return l;
}
5、数的三次方根
核心思想:浮点数二分,用l和h不断逼近最后结果,结束的条件应该为l和h的差值小于1e-7等。
保留小数:cout << fixed << setprecision(填入要保留的小数位数) << x;
代码实现:int main(){
cin >> n;
double l = -10000, h = 10000;
while(h - l > MOD){
double mid = (l + h) / 2.0;
if(mid * mid * mid <= n) l = mid;
else h = mid;
}
cout << fixed << setprecision(6) << l;
return 0;
}
6、高精度加法
要点:主函数全部倒序输入输出,执行运算的函数还是正序,要考虑到两个数的长度问题。
代码:vector<int> add(vector<int> &a, vector<int> &b){
if(a.size() < b.size()) return add(b, a);
vector<int> c;
for(int i = 0; i < a.size(); i ++ ){
t += a[i];
if(i < b.size()) t += b[i];
c.push_back(t % 10);
t /= 10;
}
if(t) c.push_back(1);
return c;
}
7、高精度减法
要点:1、写一个比较二者大小函数,a < b时,输出‘ - ’ + sub(b - a);
2、去除后面的一大堆零:while(c.size() > 1 && c.back() == 0) c.pop_back();
代码:vector<int> sub(vector<int> &a, vector<int> &b){
vector<int> c;
int t = 0;
for(int i = 0; i < a.size(); i ++ ){
t += a[i];
if(i < b.size()) t -= b[i];
if(t >= 0) {c.push_back(t % 10); t = 0;}
else {c.push_back((t + 10) % 10); t = -1;}
}
while(c.size() > 1 && c.back() == 0) c.pop_back();
return c;
}
bool cmp(vector<int> &a, vector<int> &b ){
if(a.size() > b.size()) return true;
if(a.size() < b.size()) return false;
for(int i = a.size(); i >= 0;){
if(a[i] > b[i]) return true;
if(a[i] < b[i]) return false;
if(a[i] == b[i]) i --;
}
return true;
}
8、高精度乘法
1、要点:用大数的每一位和小数相乘;处理剩余t;处理前导0。
2、代码:vector<int> mul(vector<int> a, int b){
vector<int> c;
int t = 0;
for(int i = 0; i < a.size(); i ++ ){
t += a[i] * b;
c.push_back(t % 10);
t /= 10;
}
while(t){
c.push_back(t % 10);
t /= 10;
}
while(c.size() > 1 && c.back() == 0) c.pop_back();
return c;
}
9、高精度除法
1、要点:由高位传到低位(四个中唯一);多传入一个参数:reverse(d.begin(), d.end()),无返回值。
2、代码:vector<int> mul(vector<int> a, int b){
vector<int> c;
int t = 0, re = 0;
for(int i = 0; i < a.size(); i ++ ){
t = t * 10 + a[i];
if(t / b >= 0) c.push_back(t / b);
t = t % b;
}
res = t;
// while(t){
// c.push_back(t % 10);
// t /= 10;
// }
// while(c.size() > 1 && c.back() == 0) c.pop_back();
return c;
}
10、前缀和
前缀和就不赘啦,无论是数组前缀和还是矩阵前缀和,核心思想都是前前缀和 与 此位置的数的和,把表达式照着图写清楚就好啦。
11、差分
1、要点:相当于前缀和的逆运算
2、关键代码:a[N]为前缀和数组, a[l] += c;a[r + 1] -= c;