基础算法。。。

简介: 基础算法。。。

第一讲基础算法

快速排序

void q_sort(int a[], int l, int r) 
{
    if (l >= r) return ;
    int i = l - 1, j = r + 1, x = a[l + r >> 1];
    while (i < j)
    {
        do i++; while (a[i] < x);
        do j--; while (a[j] > x);
        if (i < j) swap(a[i], a[j]);
    }
    q_sort(a, l, j);
    q_sort(a, j + 1, r);
}
void q_sort(int a[], int l, int r) 
{
    if (l >= r) return ;
    int x = a[r], i = l - 1, j = r + 1;
    while (i < j)
    {
        do i++; while (a[i] < x);
        do j--; while (a[j] > x);
        if (i < j) swap(a[i], a[j]);
    }
    q_sort(a, l, i - 1);
    q_sort(a, i, r);
}


并归排序

const int N = 1e5 + 10;
int a[N], temp[N];
void merge_sort(int a[], int l, int r)
{
    if (l >= r) return ;
    int mid = l + r >> 1;
    merge_sort(a, l, mid);
    merge_sort(a, mid + 1, r);
    int k = 0, i = l, j = mid + 1;
    while (i <= mid && j <= r)
    {
        if (a[i] <= a[j]) temp[k++] = a[i++];
        else temp[k++] = a[j++];
    }
    while (i <= mid) tmp[k++] = a[i++];
    while (j <= r) tmp[k++] = a[j++];
    for (i = 1, j = 0; i <= r; i++, j++) a[i] = tmp[j];
}


二分

转存失败重新上传取消

模板1:

while (l < r) 
{
    int mid = l + r >> 1;
    if (a[mid] >= x) r = mid;
    else l = mid + 1;
}


模板2:

while (l < r)
{
    int mid = l + r + 1 >> 1;
    if (a[mid] <= x) l = mid;
    else r = mid - 1;
}
#include<iostream>
using namespace std;
int main() {
    double x; scanf("%lf",&x);
    double l = -100, r = 100;
    while (r - l > 1e-7) 
    {
        double mid = (l + r) / 2;
        if (mid * mid * mid > x) r = mid;
        else l = mid
    }
    printf("%.6lf\n",l);
    return 0;
}


789.数的范围

#include<iostream>
using namespace std;
const int N = 1e5 + 10;
int a[N];
int main()
{
    int m ,n; scanf("%d%d", &n ,&m);
    for (int i = 0; i < n; i ++ ) scanf("%d", &a[i]);
    while ( m--)
    {
        int x; scanf("%d", &x);
        int l = 0, r = n - 1;
        while (l < r)
        {
            int mid = l + r >> 1;
            if (a[mid] >= x) r = mid;
            else l = mid + 1;
        }
        if (x != a[l]) cout << "-1 -1" << endl;
        else
        {
            cout << l << ' ';
            l = 0, r = n - 1;
            while (l < r) 
            {
                int mid = l + r + 1 >> 1;
                if (a[mid] <= x) l = mid;
                else r  = mid - 1;
            }
            cout << l << endl;
        }
    }
    return 0;
}


790.数的三次方根

#include<iostream>
using namespace std;
int main()
{
    double n; scanf("%lf", &n);
    double l = -100, r = 100;
    while (r - l > 1e-7)
    {
        double mid = (l + r) / 2;
        if (mid * mid * mid > n) r = mid;
        else l = mid;
    }
    printf("%.6lf", l);
    return 0;
}


高精度加法

找不到页面 - AcWing

vector<int> add(vector<int> &A, vector<int> &B)
{
    vector<int> C;
    int t = 0;
    for (int i = 0; i < A.size() || i < B.size(); i++) 
    {
        if (i < A.size()) 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;
}


791、高精度加法

#include<iostream>
#include<vector>
using namespace std;
vector<int> add(vector<int> &A, vector<int> &B) {
    vector<int> C;
    if (A.size() < B.size()) swap(A, B);
    int t = 0;
    for (int i = 0; i < A.size(); i++)
    {
        if (i < A.size()) t += A[i];
        if (i < B.size()) t += B[i];
        C.push_back(t % 10);
        t /= 10;
    }
    if (t) C.push_back(t);
    return C;
}
int main() {
    string a, b; cin >> a >> b;
    vector<int> A, B;
    for (int i = a.size() - 1; i >= 0; i -- ) A.push_back(a[i] - '0');
    for (int i = b.size() - 1; i >= 0; i -- ) B.push_back(b[i] - '0');
    vector<int>C = add(A, B);
    for (int i = C.size() - 1; i >= 0; i--) cout << C[i];
    return 0;
}


高精度减法

bool cmp(vector<int> &A, vector<int> &B)
{
    if (A.size() != B.size()) return A.size() > B.size();
    for (int i = A.size() - 1; i >= 0; i--)
        if (A[i] != B[i])
            return A[i] > B[i];
    return true;
}
vector<int> sub(vector<int> &A, vector<int> &B)
{
    vector<int> C;
    for (int i = 0,t = 0; i < A.size(); i++)
    {
        t = A[i] - t;
        if (i < B.size()) t -= B[i];
        C.push_back((t + 10) % 10);
        if (t < 0) t = 1;
        else t = 0;
    }
    while (C.size() > 1 && C.back() == 0) C.pop_back();
    return C;
}


793、高精度乘法

#include<iostream>
#include <vector>
using namespace std;
vector<int> mul(vector<int> &A, int b)
{
    vector<int> C;
    int t = 0;
    for (int i = 0; i < A.size() || t; i++)
    {
        if (i < A.size()) t += A[i] * b;
        C.push_back(t % 10);
        t /= 10;
    }
    if (t) C.push_back(t);
    while (C.back() == 0 && C.size() > 1) C.pop_back();
    return C;
}
int main()
{
    string a; 
    int b; cin >> a >> b;
    vector<int>A, C;
    for (int i = a.size() -1; i >= 0; i -- ) A.push_back(a[i] - '0');
    C = mul(A,b);
    for (int i = C.size() - 1; i >= 0; i --) cout << C[i];
    return 0;
}


高精度除法

vector<int> div(vector<int> &A, int b, int &r)
{
    vector<int> C;
    r = 0;
    for (int i = A.size() - 1; i >= 0; i--)
    {
        r = r * 10 + A[i];
        C.push_back(r / b);
        r %= b;
    }
    reverse(C.begin(), C.end());
    while (C.back() == 0 && C.size() > 1) C.pop_back();
    return C;
}


794.高精度除法

#include<iostream>
#include <vector>
#include<algorithm>
using namespace std;
vector<int> div(vector<int> &A, int b, int &r)
{
    vector<int> C;
    r = 0;
    for (int i = A.size() - 1; i >= 0; i--)
    {
        r = r * 10 + A[i];
        C.push_back(r / b);
        r %= b;
    }
    reverse(C.begin(), C.end());
    while (C.back() == 0 && C.size() > 1) C.pop_back();
    return C;
}
int main()
{
    string a;
    int b; cin >> a >> b;
    vector<int>A, C;
    for (int i = a.size() - 1; i >= 0; i--) A.push_back(a[i] - '0');
    int r;
    C = div(A, b, r);
    for (int i = C.size() - 1; i >= 0; i--) cout << C[i];
    cout << endl << r << endl;
    return 0;
}795前缀和
#include<iostream>
using namespace std;
const int N = 1e5 + 10;
int n, m;
int a[N], s[N];
int main()
{
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
    s[0] = 1;
    for (int i = 1; i <= n; i++)
    {
        s[i] = s[i - 1] + a[i];
    }
    while (m -- ) 
    {
        int l , r;
        scanf("%d%d", &l, &r);
        printf("%d\n", s[r] - s[l - 1]);
    }
    return 0;
}


前缀额和差分

796.前缀和

#include<iostream>
using namespace std;
const int N = 1e5 + 10;
int n, m;
int a[N], s[N];
int main()   
{
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
    s[0] = 1;
    for (int i = 1; i <= n; i++)
    {
        s[i] = s[i - 1] + a[i];
    }
    while (m -- ) 
    {
        int l , r;
        scanf("%d%d", &l, &r);
        printf("%d\n", s[r] - s[l - 1]);
    }
    return 0;
}


796.子矩阵的和

#include<iostream>
using namespace std;
const int N = 1010;
int n, m, q;
int a[N][N], s[N][N];
int main()
{
    scanf("%d%d%d",&n,&m,&q);
    for (int i = 1 ; i <= n; i++)
        for (int j = 1; j <= m; j++)
            scanf("%d",&a[i][j]);
    for (int i = 1; i <= n; i ++ )
        for (int j = 1; j <= m; j ++ )
            s[i][j] = s[i- 1][j] + s[i][j - 1] - s[i - 1][j - 1] + a[i][j];
    while (q -- )
    {
        int x1, y1, x2, y2;
        scanf("%d%d%d%d",&x1, &y1, &x2, &y2);
        printf("%d\n", s[x2][y2] - s[x1 - 1][y2] -s[x2][y1 -1] + s[x1 - 1][y1 - 1]);
    }
    return 0;
}


797.差分

#include<iostream>
using namespace std;
const int N = 1e5 + 10;
int n, m;
int a[N], b[N];
void insert(int l, int r, int c)
{
    b[l] += c;
    b[r + 1] -= c;
}
int main()
{
    scanf("%d%d", &n ,&m);
    for (int i = 1; i <= n; i++)
    {
        scanf("%d", &a[i]);
        insert(i, i, a[i]);
        //b[i] = a[i] - a[i - 1];
    }
    int l, r, c;
    while (m -- )
    {
        scanf("%d%d%d", &l, &r, &c);
        insert(l ,r, c);
    }
    for (int i = 1; i <= n; i++)
    {
        b[i] += b[i - 1];
        printf("%d ",b[i]);
    }
    return 0;
}


798.差分矩阵

#include<iostream>
using namespace std;
const int N = 1010;
int a[N][N], b[N][N];
int n, m, q;
void insert(int x1, int y1, int x2, int y2, int c)
{
    b[x1][y1] += c;
    b[x2 + 1][y1] -= c;
    b[x1][y2 + 1] -= c;
    b[x2 + 1][y2 + 1] += c;
}
int main()
{
    scanf("%d%d%d", &n, &m, &q);
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= m; j++)
        {
            scanf("%d", &a[i][j]);
            insert(i, j, i, j, a[i][j]);
        }
    }
    // for (int i = 1; i <= n; i++)
    //     for (int j = 1; j <= m; j++)
    //         insert(i, j, i, j, a[i][j]);
    int x1, y1, x2, y2, c;    
    while (q--)
    {
        scanf("%d%d%d%d%d", &x1, &y1, &x2, &y2, &c);
        insert(x1, y1, x2, y2, c);
    }
    // for (int i = 1; i <= n; i++)
    //     for (int j = 1; j <= m; j++)
    //         b[i][j] += b[i - 1][j] + b[i][j  -1] - b[i - 1][j - 1];
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= m; j++)
        {
            b[i][j] += b[i - 1][j] + b[i][j  -1] - b[i - 1][j - 1];
            printf("%d ", b[i][j]);
        }
        printf("\n");
    }
    return 0;
}


双指针算法

799.最长连续不重复子序列

#include<iostream>
using namespace std;
const int N = 100010;
int a[N], b[N];
int main()
{
    int n;
    scanf("%d", &n);
    for (int i = 0; i < n; i++) scanf("%d", &a[i]);
    int res = 0;
    for (int i = 0, j = 0; i < n; i++)
    {
        b[a[i]]++;
        while (b[a[i]] > 1) 
        {
            b[a[j]]--;
            j++;
        }
        res = max(res, i - j + 1);
    }
    cout << res;
    return 0;
}


800.数组元素的目标和

#include<iostream>
using namespace std;
const int N = 1e5 + 10;
int a[N], b[N];
int n, m, x;
int main()
{
    scanf("%d%d%d", &n, &m, &x);
    for (int i = 0; i < n; i++) scanf("%d", &a[i]);
    for (int i = 0; i < m; i++) scanf("%d", &b[i]);
    int j = m - 1;
    for (int i = 0; i < n; i++)
    {
        while (j >= 0 && a[i] + b[j] > x) j--;
        if (a[i] + b[j] == x) printf("%d %d" ,i ,j);
    }
    return 0;
} 
2816.判断子序列
#include<iostream>
using namespace std;
const int N = 1e5 + 10;
int n ,m;
int a[N], b[N];
int main()
{
    scanf("%d%d", &n, &m);
    for (int i = 0; i < n; i++) scanf("%d", &a[i]);
    for (int i = 0; i < m; i++) scanf("%d", &b[i]);
    int i = 0, j = 0;
    while (i < n && j < m)
    {
        if (a[i] == b[j]) i++;
        j++;
    }
    if (i == n) puts("Yes");
    else puts("No");
    return 0;
}



位运算

801.二进制中一的个数

#include<iostream>
using namespace std;
int main()
{
    int n;
    scanf("%d", &n);
    while (n--)
    {
        int x, res = 0;
        scanf("%d", &x);
        for (int i = x; i; i -= i & -i) res++;
        cout << res << ' ';
    }
    return 0;
}


离散化

vector<int> alls; //存储所有待离散化的值
sort(alls.bedin(), alls.end()); // 将所有值排序
alls.earse(unique(alls.begin(), alls.end()), alls.end()); //去掉重复元素
//二分求出x对应的离散化的值
int find(int x) // 找到第一个大于等于 x 的位置
{
    int l = 0, r = alls.size() - 1;
    while (l < r)
    {
        int mid = l + r >> 1;
        if (alls[mid] >= x) r = mid;
        else l = mid + 1;
    }
    return r + 1; //映射到 1, 2, 3, ...n
}


802.区间和

https://www.acwing.com/activity/content/problem/content/836/

unique在stl中的使用

https://blog.csdn.net/qq_36561697/article/details/82356053

#include <iostream>
#include <vector>
#include<algorithm>
using namespace std;
typedef pair<int, int> PII;
const int N = 300010;
int n, m;
int a[N], s[N];
vector<int> alls;
vector<PII> add, query;
int find(int x)
{
    int l = 0, r = alls.size() - 1;
    while (l < r)
    {
        int mid = l + r >> 1;
        if (alls[mid] >= x) r = mid;
        else l = mid + 1;
    }
    return r + 1;
}
int main()
{
    cin >> n >> m;
    for (int i = 0; i < n; i++)
    {
        int x, c;
        cin >> x >> c;
        add.push_back({x, c});
        alls.push_back(x);
    }
    for (int i = 0; i < m; i++)
    {
        int l ,r;
        cin >> l >> r;
        query.push_back({l, r});
        alls.push_back(l);
        alls.push_back(r);
    }
    // 去重
    sort(alls.begin(), alls.end());
    alls.erase(unique(alls.begin(), alls.end()), alls.end());
    // 处理插入
    for (auto item : add) a[find(item.first)] += item.second;
    // 预处理前缀和
    for (int i = 1; i <= alls.size(); i++)
        s[i] = s[i - 1] + a[i];
    // 处理询问
    for (auto item : query)
    {
        int l = find(item.first), r = find(item.second);
        cout << s[r] - s[l - 1] << endl;
    }
    return 0;
}


803.区间合并

https://www.acwing.com/activity/content/problem/content/837/

void merge(vector<PII> &segs){
    vector<PII> res;
    // 左端点排序
    sort(segs.begin(), segs.end());
    // 左右端点初始化,-无穷
    int start = -2e9, end = -2e9;
    for(auto seg: segs){
        if(end < seg.first){
            // 初始的[-无穷,-无穷]区间要跳过,不能装入
            if(start != -2e9) res.push_back({start, end});
            start = seg.first, end = seg.second;
        }
        else end = max(end, seg.second);
    }
    // 有两个作用,1.是防止n为0,把[-无穷,-无穷]压入;2.是压入最后一个(也就是当前)的区间,若n>=1,if可以不要
    if (start != -2e9) res.push_back({start, end});
    //覆盖segs
    segs = res;
}


第二讲数据结构

单链表

826.单链表


双链表

827.双链表


828.模拟栈

3302.表达式求值


队列

829.模拟队列


单调栈

830.单调栈


单调队列

154.滑动窗口


KMP

831.KMP字符串

835.Tire字符串统计

143.最大异或对


并查集

并查集

1、将两个集合和合并

2、询问两个集合是否在一个集合当中

belong[x] = a

if (belong[x] == belong[y]) o(1)


基本原理:每个集合用一颗树来表示。树根的编号就是整个集合的编号。每个结点存储它的父节点,p[x]表示x的父节点

问题1:如何判断树根:if(p[x] == x)

问题2:如何求x的集合编号:while (p[x] != x) x = p[x];

问题3:如何合并两个集合:p[x] 是 x的 集合编号,py是y的集合号。p[x] = y


find(x) 和 find(p[x])有啥区别?不都是返回祖宗节点么?

p[x]是x的父节点,满足p[x]==x的是根节点,find(p[x])相当于找父节点的父节点,逐层往上找

确实都是返回祖宗结点,没区别

find(x)会进入死循环


836.合并集合

https://www.acwing.com/activity/content/problem/content/885/

#include <iostream>
using namespace std;
const int N = 1e5 + 10;
int n, m;
int p[N];
int find (int x)
{
    if (x != p[x]) p[x] = find(p[x]);
    return p[x];
}
int main()
{
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++) p[i] = i;
    while (m -- )
    {
        int a, b;
        char op[2];
        scanf("%s%d%d", op, &a, &b);
        if (op[0] == 'M') p[find(a)] = find(b);
        else
        {
            if (find(a) != find(b)) puts("No");
            else puts("Yes");
        }
    }
    return 0;
}


837.连通块中的点数量

https://www.acwing.com/activity/content/problem/content/886/

#include<iostream>
using namespace std;
const int N = 1e5 + 10;
int n, m;
int p[N], cnt[N];
int find (int x)
{
    if (x != p[x]) p[x]=find(p[x]);
    return p[x];
}
int main()
{
    scanf("%d%d", &n, &m);
    for (int i = 1; i <=n; i++)
    {
        p[i] = i;
        cnt[i] = 1;
    }
    while (m -- )
    {
        char op[3];
        int a, b;
        scanf("%s", op);
        if (op[0] == 'C') 
        {
            scanf("%d%d", &a, &b);
            if (find(a) == find(b)) continue;
            cnt[find(b)] += cnt[find(a)];
            p[find(a)] = find(b);
        }
        else if (op[1] == '1') 
        {
            scanf("%d%d", &a, &b);
            if (find(a) == find(b)) puts("Yes");
            else puts("No");
        }
        else if (op[1] == '2')
        {
            scanf("%d", &a);
            printf("%d\n", cnt[find(a)]);
        }
    }
    return 0;
}




目录
相关文章
|
7月前
|
存储 算法 数据管理
【C/C++ 基础算法】 C/C++ 位图算法的使用
【C/C++ 基础算法】 C/C++ 位图算法的使用
116 0
|
算法 测试技术
经典算法:最短点对
经典算法:最短点对
|
7月前
|
算法
基础算法题
基础算法编程题
26 3
|
7月前
|
机器学习/深度学习 存储 算法
基础算法学习笔记(C++)
基础算法学习笔记(C++)
81 0
|
算法 C++
【基础算法】开平方算法 & C++实现
在数学中,因为很多数的开平方都是无理数,所以我们需要借助数值计算的方式来进行近似值的求解。
334 0
【基础算法】开平方算法 & C++实现
|
机器学习/深度学习 存储 自然语言处理
蓝桥杯系列3——基础算法
蓝桥杯系列3——基础算法
74 0
|
算法
【学习挑战赛】经典算法之折半查找
【学习挑战赛】经典算法之折半查找
175 0
|
存储 算法 大数据
基础算法-高精度乘法
高精度算法 为什么要使用高精度算法 C++ 每一个变量都有自己的类型,每个类型都有自己的存储长度范围
|
算法 C++