第一讲 基础算法

1.快速排序

AcWing 785. 快速排序

https://www.acwing.com/problem/content/787/

点击查看代码
#include <iostream>
using namespace std;
const int N = 100010;
int a[N],n;
void quick_sort(int a[],int l,int r){
    if(l >= r) return;
    int i = l-1,j = r+1, x = a[l + r >> 1];
    // a[l, i] a[j,r] 区间内必成立 
    // ①当左边i找到比x大的元素,右边找不到比x小的元素, j-- j--直到  j < i, a[i] > x  a[j] < x。 a[l,j] a[j+1,r] 是合理的

    //② 当左边i找不到比x大的元素,i++ i++ 直到 i == j, a[i]==a[j] > x 然后 do j--; a[j] < x , swap(a[i],a[j]); a[i] < x, a[j] > x; a[l,j] a[j+1,r] 是合理的
    //③ 当左边找到,右边也找到,那么合理
   
    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,r);
}
int main(){
    cin >> n;
    for(int i = 1; i <= n; i++) cin >> a[i];
    quick_sort(a,1,n);
    for(int i = 1; i <= n; i++) cout << a[i] << " ";
}
点击查看代码
#include <iostream>
#include <stdlib.h>
#include <cmath>
#include <algorithm>
using namespace std;

const int N = 100010;
int a[N];
int n;
void quick_sort(int a[],int l,int r){
    if(l >= r) return;
    swap(a[l],a[(l+r) >> 1]);
    int pivot = a[l],i = l,j = r;
    // 原先的写法: while(a[j] >= pivot && i < j) j--;
    // 这样会忽略与支点相同的元素
    // 数组的所有数字全都一样,那么 i == j == l; 外层while(i < j)直接结束了,陷入死循环
    // while(a[j] > pivot && i < j) j--; 把支点相同的元素也进行操作
    // 
    while(i < j){
        while(a[j] > pivot &&  i < j) j--;
        a[i] = a[j];
        if(i < j) i++;
        while(a[i] < pivot && i < j) i++;
        a[j] = a[i];
        if(i < j) j--;
    }
    a[i] = pivot;
    quick_sort(a,l,i-1);
    quick_sort(a,i+1,r);
}

int main(){
    ios::sync_with_stdio(false); cin.tie(0);
    cin >> n;
    for(int i = 1; i <= n; i++) cin >> a[i];
    quick_sort(a,1,n);
    for(int i = 1; i <= n; i++) cout << a[i] << " ";


    return 0;
}

AcWing 786. 第k个数

https://www.acwing.com/problem/content/788/

点击查看代码
#include <iostream>
using namespace std;
const int N = 100010;
int a[N];
int n,k;
int quick_sort(int a[],int l,int r,int k){
    if(l == r) return a[l];
    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]);
    }
    //快排不确定支点的最终位置
    int t = j-l + 1;
    if(t >= k) return quick_sort(a,l,j,k);
    else return quick_sort(a,j+1,r,k-t);
}
int main(){
    cin >> n >> k;
    for(int i = 1; i <= n; i++) cin >> a[i];
    cout << quick_sort(a,1,n,k) << endl;
    return 0;
}
点击查看代码
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 100010;
int a[N];
int n,k;

int quick_sort(int a[],int l,int r){
    if(l == r) return a[l];

    if(l < r){
        int pivot = a[l],i = l,j = r;
        while(i < j){
            while(a[j] > pivot && i < j) j--;
            a[i] = a[j];
            if(i < j) i++;
            while(a[i] < pivot && i < j) i++;
            a[j] = a[i];
            if(i < j) j--;
        }
        a[i] = pivot;
        if(i == k) return a[i];
        if(i > k) return quick_sort(a,l,i-1); // important
        if(i < k) return quick_sort(a,i+1,r);
    }
}

int main(){
    cin >> n >> k;
    for(int i = 1; i <= n; i++) cin >> a[i];
    
    cout << quick_sort(a,1,n) << endl;
    return 0;
}

2. 归并排序

AcWing 787. 归并排序

https://www.acwing.com/problem/content/789/

点击查看代码
#include <iostream>
using namespace std;

const int N = 100010;
int n;
int a[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 i = l,j = mid+1;
    int b[r-l+2],k = 0;
    while(i <= mid && j <= r){
        if(a[i] <= a[j]) b[k++] = a[i++];
        else b[k++] = a[j++];
    }
    while(i <= mid) b[k++] = a[i++];
    while(j <= r) b[k++] = a[j++];
    for(int p = l,q = 0; p <= r; p++,q++){
        a[p] = b[q];
    }
}

int main(){
    cin >> n;
    for(int i = 1; i <= n; i++) cin >> a[i];
    merge_sort(a,1,n);
    for(int i = 1; i <= n; i++) cout << a[i] << " ";
    return 0;
}

AcWing 788. 逆序对的数量

https://www.acwing.com/problem/content/790/

点击查看代码

image

#include <iostream>
using namespace std;
typedef long long LL;
const int N = 100010;
int n;
int a[N];
LL res;

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;
    int temp[r-l+2];
    while(i <= mid && j <= r){
        if(a[i] <= a[j]) temp[k++] = a[i++];
        else {
            temp[k++] = a[j++];
            res += mid-i+1;
        }
    }
    //扫尾
    while(i <= mid) temp[k++] = a[i++];
    while(j <= r) temp[k++] = a[j++];
    //物归原主
    for(int p = l,q = 0; p <= r; p++,q++){
        a[p] = temp[q];
    }
}

int main(){
    
    cin >> n;
    for(int i = 1; i <= n; i++) cin >> a[i];
    merge_sort(a,1,n);
    cout << res << endl;
    
    
    return 0;
}

3.二分

点击查看代码

必须是 l <= r,
不然 a1,a2 mid = a1下标, a1可以找到 a2会找不到

int binary_search(int a[],int l,int r,int target){
    while(l <= r){
        int mid = l + (r-l)/2;
        if(a[mid] == target) return mid;
        if(a[mid] < target) l = mid + 1;
        else r = mid - 1;
    }
    return -1;
}

lower_bound

即 lower_bound:如果数组中存在和target相等的数,那么结果就是相等最左边的数,否则返回 > target最小的数的下标

点击查看代码
// 返回的范围 [0,a.length]
// a[l] > target, 当target最小,l == r会死循环
// a[l] == target, 找到了,跳出来
int l_b(int a[],int l,int r,int target){
    while(l <= r){
        int mid = l + (r-l)/2;
        if(l == r && a[l] >= target) break;
        if(a[mid] < target) l = mid + 1;
        else r = mid; //等于时取最左边
    }
    return l;
}

upper_bound

即 upper_bound:> target 的最小的那个数的下标

点击查看代码
int u_b(int a[],int l,int r,int target){
	while(l <= r){
		int mid = l + (r-l)/2;
		if(l == r && a[mid] > target) break;
		if(a[mid] <= target) l = mid + 1;
		else r = mid;
	}
	return l;
}

AcWing 789. 数的范围

https://www.acwing.com/problem/content/791/

点击查看代码
#include <iostream>
using namespace std;

const int N = 100010;

int a[N];
int n,q,k;
int l_b(int target){
    int l = 0, r = n-1;
    while(l <= r){
        int mid = l + (r-l)/2;
        if(l == r && a[mid] >= target) break;
        if(a[mid] < target) l = mid + 1;
        else r = mid;
    }
    return l;
}
int u_b(int target){
    int l = 0, r = n-1;
    while(l <= r){
        int mid = l + (r-l)/2;
        if(l == r && a[mid] > target) break;
        if(a[mid] <= target) l = mid + 1;
        else r = mid;
    }
    return l;
}
int main(){
    cin >> n >> q;
    for(int i = 0; i < n; i++) cin >> a[i];
    while(q--){
        int k; cin >> k;
        int t1 = l_b(k), t2 = u_b(k) - 1;
        if(a[t1] != k) cout << -1 << " ";
        else cout << t1 << " ";
        if(t2 >= 0 && t2 < n && a[t2] == k) cout << t2 << endl;
        else cout << -1 << endl;
    }
}

790. 数的三次方根

https://www.acwing.com/problem/content/description/792/

点击查看代码

在[-100,100]上二分一个数,使 r-l 的范围(精度) < 0.0000001
然后根据题中条件去缩小 l,r的范围

#include <iostream>
#include <cstdio>
using namespace std;

int main(){
    double n; cin >> n;
    double l = -100,r = 100;
    while(r-l > 0.0000001){
        double mid = l + (r-l)/2;
        if(mid * mid * mid < n) l = mid;
        else r = mid;
    }
    printf("%.6lf",l);
    
}

4.高精度

AcWing 791. 高精度加法

https://www.acwing.com/problem/content/793/

点击查看代码
#include <iostream>
#include <vector>
using namespace std;
vector<int> va,vb,vc;


int main(){
    string sa,sb; cin >> sa >> sb;
    for(int i = sa.length()-1; i >= 0; i--) va.push_back(sa[i]-'0');
    for(int i = sb.length()-1; i >= 0; i--) vb.push_back(sb[i]-'0');
    
    long unsigned int  i = 0, j = 0,t = 0;
    while(i <= va.size()-1 || j <= vb.size()-1){
        if(i <= va.size()-1) t += va[i++];
        if(j <= vb.size()-1) t += vb[j++];
        vc.push_back(t%10);
        t /= 10;
    }
    if(t != 0) vc.push_back(t);
    
    for(int i = vc.size()-1; i >= 0; i--) cout << vc[i];
    
    
}

AcWing 792. 高精度减法

https://www.acwing.com/problem/content/794/

点击查看代码
#include <iostream>
#include <vector>
using namespace std;



int cmp(vector<int> va,vector<int> vb){
    if(va.size() != vb.size()) return va.size() > vb.size();
    for(int i = va.size()-1; i >= 0; i--){
        if(va[i] == vb[i]) continue;
        return va[i] > vb[i];
    }
}

int main(){
    string sa,sb; cin >> sa >> sb;
    vector<int> va,vb,vc;
    for(int i = sa.length()-1; i >= 0; i--) va.push_back(sa[i] - '0');
    for(int i = sb.length()-1; i >= 0; i--) vb.push_back(sb[i] - '0');

    if(cmp(va,vb)){
        int t = 0; //借位
        for(int i = 0; i <= va.size()-1; i++){
            va[i] += t;
            if(i <= vb.size()-1) va[i] -= vb[i];
            vc.push_back((va[i] + 10) % 10);
            if(va[i] < 0) t = -1;
            else t = 0; // important, 不然 不该借位的时候也借位了
        }
    }else{
        cout << "-";
        int t = 0;
        for(int i = 0; i <= vb.size()-1; i++){
            vb[i] += t;
            if(i <= va.size()-1) vb[i] -= va[i];
            vc.push_back((vb[i] + 10) % 10);
            if(vb[i] < 0) t = -1;
            else t = 0;
        }
    }
     //去掉前置0(高位0),000->00
    while(vc.size() > 1 && vc.back() == 0) vc.pop_back();
    for(int i = vc.size()-1; i >= 0; i--) cout << vc[i];
    
    return 0;
}

AcWing 792. 高精度减法

https://www.acwing.com/problem/content/description/795/

点击查看代码
#include <iostream>
#include <vector>
using namespace std;

int main(){
	string sa,sb; cin >> sa >> sb;
	vector<int> va,vb;
	for(int i = sa.length()-1; i >= 0; i--) va.push_back(sa[i]-'0');
	for(int i = sb.length()-1; i >= 0; i--) vb.push_back(sb[i]-'0');
	vector<int> vc(va.size() + vb.size() + 11,0);
	// va * vb , 用vb的个位乘以va的每一位
	for(int i = 0; i < vb.size(); i++){
		for(int j = 0; j < va.size(); j++){
			int t = vc[i+j] + vb[i] * va[j];
			vc[i+j] = t % 10;
			vc[i+j+1] += t / 10;
		}
	}
	//去前置0
	while(vc.size() > 1 && vc.back() == 0) vc.pop_back();
	for(int i = vc.size()-1; i >= 0; i--) cout << vc[i];

	return 0;
}

AcWing 794. 高精度除法

https://www.acwing.com/problem/content/796/
一个大数除以一个小数
让这个小数转为int
大数从高位开始除, x为余数

点击查看代码
#include <iostream>
#include <vector>
#include <deque>
using namespace std;

/** 
 * 88
 * 2
**/
int x = 0; //余数
deque<int> div(vector<int>& a,int b){
	//a是被除数,b是除数
	deque<int> c(a.size()); //商集合
	for(int i = 0; i < a.size(); i++){
		c[i] = (x*10 + a[i]) / b;
		x = (x*10 + a[i]) % b;
	}
	while(c.size() > 1 && c.front() == 0) c.pop_front(); //注意清除的是前置0
	return c;
}

int main(){
	// s1 >= s2
	string s1,s2; cin >> s1 >> s2;
	vector<int>a;
	for(int i = 0; i < s1.length(); i++) a.push_back(s1[i]-'0');
	int b = 0;
	for(int i = 0; i < s2.length(); i++){
		b = b*10;
		b += s2[i]-'0';
	}

	deque<int> c = div(a,b);
	for(int i = 0; i < c.size(); i++) cout << c[i];
	cout << endl << x << endl;

	return 0;
}

5.前缀和与差分

AcWing 795. 前缀和

https://www.acwing.com/problem/content/797/

点击查看代码
#include <iostream>
using namespace std;

const int N = 100010;
int a[N],b[N];
int n,m;
int l,r;

int main(){
	cin >> n >> m;
	for(int i = 1; i <= n; i++) cin >> a[i];
	for(int i = 1; i <= n; i++) b[i] += a[i] + b[i-1];
	while(m--){
		cin >> l >> r;
		cout << b[r] - b[l-1]<< endl;
	}
	

	return 0;
}

AcWing 796. 子矩阵的和

https://www.acwing.com/problem/content/798/

点击查看代码
#include <iostream>
using namespace std;

const int N = 1000 + 11;
int a[N][N],b[N][N];
int n,m,q;
int x1,y1,x2,y2;

int main(){
    cin >> n >> m >> q;
    for(int i = 1; i <= n; i++){
        for(int j = 1; j <= m; j++){
            cin >> a[i][j];
        }
    }
    for(int i = 1; i <= n; i++){
        for(int j = 1; j <= m; j++){
              b[i][j] = a[i][j] +  b[i-1][j] + b[i][j-1] - b[i-1][j-1];
        }
    }
    while(q--){
        cin >> x1 >> y1 >> x2 >> y2;
        cout << b[x2][y2]  - b[x1-1][y2] -b[x2][y1-1]+ b[x1-1][y1-1]  << endl;
    }
    
    return 0;
}

AcWing 797. 差分

a数组的每一个数都是 b数组从0开始的前缀和
https://www.acwing.com/solution/content/26588/

点击查看代码

image

image

#include <iostream>
using namespace std;
const int N = 100010;
int a[N],b[N];
int n,m,l,r,c;

int main(){
    cin >> n >> m;
    for(int i = 1; i <= n; i++) cin >> a[i];
    for(int i = 1; i <= n; i++) b[i] = a[i] - a[i-1];
    while(m--){
        cin >> l >> r >> c;
        b[l] += c;
        b[r+1] -= c;
    }
    int t = 0;
    for(int i = 1; i <= n; i++){
        t += b[i]; 
        cout << t << " ";
    }
    return 0;
}

AcWing 798. 差分矩阵

6.双指针算法

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

https://www.acwing.com/problem/content/801/

点击查看代码
#include <iostream>
using namespace std;

const int N = 100010;
int q[N],s[N];
int n;

int main(){
    cin >> n;
    for(int i = 1; i <= n; i++) cin >> q[i];
    int res = 0;
    for(int i = 1,j = 1; i <= n; i++){
        s[q[i]]++;
        // 在[j,i]区间内都要防止有重复的元素
        while(j < i && s[q[i]] > 1) s[q[j++]]--;
        res = max(res,i-j+1);
    }
    cout << res << endl;
    return 0;
}
点击查看代码 - unordered_map
#include <iostream>
#include <unordered_map>
using namespace std;

const int N = 100010;
int q[N];
int n;
unordered_map<int,int> ump;

int main(){
    cin >> n;
    for(int i = 1; i <= n; i++) cin >> q[i];
    int res = 0;
    for(int i = 1,j = 1; i <= n; i++){
        ump[q[i]]++;
        // 在[j,i]区间内都要防止有重复的元素
        while(j < i && ump[q[i]] > 1) ump[q[j++]]--;
        res = max(res,i-j+1);
    }
    cout << res << endl;
    return 0;
}

AcWing 800. 数组元素的目标和(two_sum)

https://www.acwing.com/problem/content/802/

点击查看代码
#include <iostream>
using namespace std;
const int N = 100010;
int a[N],b[N];
int n,m,x;
int main(){
    cin >> n >> m >> x;
    for(int i = 0; i < n; i++) cin >> a[i];
    for(int i = 0; i < m; i++) cin >> b[i];
    for(int i = 0,j = m-1; i < n; i++){
        while(j > 0 && b[j] + a[i] > x) j--;
        if(b[j] + a[i] == x){
            cout << i << " " << j << endl;
            break;
        }
    }
    return 0;
}
点击查看代码_unordered_map查找
#include <iostream>
#include <unordered_map>
using namespace std;

const int N = 100010;

int a[N];
unordered_map<int,int> mp;


int main(){
    int n,m,x; scanf("%d%d%d",&n,&m,&x);
    for(int i = 1; i <= n; i++) scanf("%d",&a[i]);
    for(int i = 1; i <= m; i++){
        int t; scanf("%d",&t);
        mp[t] = i;
    }
    for(int i = 1; i <= n; i++){
        if(mp.count(x-a[i])){
            printf("%d %d\n",i-1,mp[x-a[i]]-1);
            break;
        }
    }
    
    
    
    
    return 0;
}

AcWing 2816. 判断子序列

https://www.acwing.com/problem/content/803/

点击查看代码
#include <iostream>
using namespace std;

const int N = 100010;
int n,m;
int a[N],b[N];
int main(){
    cin >> n >> m;
    for(int i = 1; i <= n; i++) cin >> a[i];
    for(int i = 1; i <= m; i++) cin >> b[i];
    bool isok = false;
    for(int i = 1, j = 1; i <= n; i++){
        while(j < m && a[i] != b[j]) j++;
        if(i == n && j <= m && a[i] == b[j]){ // 防止越界
            isok = true;
            break;
        }
        j++;
    }
    if(isok) cout << "Yes" << endl;
    else cout << "No" << endl;
    return 0;
}
点击查看代码-y总
#include <iostream>
#include <cstring>

using namespace std;

const int N = 100010;

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;
}

7.位运算

AcWing 801. 二进制中1的个数

点击查看代码
#include <iostream>
using namespace std;
const int N = 100010;
int a[N];

int main(){
    int n; cin >> n;
    for(int i = 1; i <= n; i++) cin >> a[i];
    for(int i = 1; i <= n; i++){
        int res = 0;
        for(int k = 31; k >= 0; k--) res += (a[i] >> k & 1);
        cout << res << " ";
    }
    
    return 0;
}
点击查看代码
#include <iostream>
using namespace std;
const int N = 100010;
int a[N];
int lowbit(int x){
    return x&(-x);
}

int main(){
    int n; cin >> n;
    for(int i = 1; i <= n; i++) cin >> a[i];
    for(int i = 1; i <= n; i++){
        int res = 0;
        while(a[i]) a[i] -= lowbit(a[i]), res++;
        cout << res << " ";
    }
    
    return 0;
}
posted @   超级氯化钾  阅读(37)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
点击右上角即可分享
微信分享提示