算法基础课第一章(学习笔记)

目录

1、快速排序

2、归并排序

3、求逆序对

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;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值