acwing算法模板

 常见结论:

循环读入带空格的字符串,直到字符串为空,结束输入:

 string input;
    while (true) {
        cout << "请输入字符串(输入为空时将停止):" << endl;
        getline(cin, input);
        if (input.empty()) {
            break;
        }
        // 在这里处理读取到的字符串
        cout << "输入的字符串是:" << input << endl;
    }
    cout << "循环结束" << endl;

1.快速排序

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

2.归并排序

void guibin(int q[],int l,int r) {
    if (l >= r)return;
    int mid= l + r >> 1;//定义为中间的数。
    guibin(q, l, mid);//处理左边
    guibin(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 (int i = l, j = 0; i <= r; i++, j++)q[i] = tmp[j];//将结果存入q数组
}

3.二分

int SL(int l, int r, int x) {//左边界
  while (l < r) {
    int mid = l + r >> 1;
    if (q[mid] >= x) r = mid;
    else l = mid + 1 ;
  }
  return l;
}

int SR (int l, int r, int x) {//右边界
  while (l < r) {
    int mid = l + r + 1 >> 1;
    if(q[mid] <= x) l = mid;
    else r = mid - 1;
  }
  return r;
}

 4.前缀和

一维前缀和:

求和:s[i]=s[i-1]+a[i];

求l到r部分:s[r]-s[l-1];

二维前缀和:

求和:s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1]+a[i][j];

求(x1,y1)到(x2,y2)部分:s[x2][y2]-s[x2][y1-1]-s[x1-1][y2]+s[x1-1][y1-1];

5.差分

一维差分:

在l和r部分加c:a[l]+=c;a[r+1]-=c;

二维差分:

在(x1,y1)和(x2,y2)部分加c:a[x1][y1]+=c;a[x2+1][y1]-=c;a[x1][y2+1]-=c;a[x2+1][y2+1]+=c;

6.二进制中1的个数

long long lowbit(long long x){//返回x二进制中最后一位1
return x&-x;
}
int main(){
long long x;
scanf("%lld",&x);
int ans=0;
while(x){
x-=lowbit(x);
ans++;
}
cout<<ans;
return 0;
}

 7.单链表

const int N=1e6+10;
int h[N], e[N], ne[N], head, idx;
int n;
void init(){
    head=-1;
    idx=0;
}

void int_to_head(int x){
    e[idx]=x;
    ne[idx]=head;
    head=idx;
    idx++;
}

void add(int k,int x){
    e[idx]=x;
    ne[idx]=ne[k];
    ne[k]=idx;
    idx++;
}
void remove(int k){
    ne[k] = ne[ne[k]];
}

 8.双链表

const int N = 1e5 + 10;
int m;
int e[N], l[N], r[N];
int idx;
void init() {
	l[1] = 0, r[0] = 1;
	idx = 2;
}
//在第k个点右边插入一个x
void add(int k, int x) {
	e[idx] = x;
	l[idx] = k;
	r[idx] = r[k];
	l[r[k]] = idx;
	r[k] = idx++;
}
void remove(int k) {
	r[l[k]] = r[k];
	l[r[k]] = l[k];
}

9.模拟栈

const int N = 1e5 + 10;
int stk[N],tt;
//从栈顶弹出一个数
void pop() {
	tt--;
}
bool empty() {
	if (tt > 0)cout << "NO" << endl;
	else cout<<"YES"<<endl;
}
void query() {
	cout << stk[tt] << endl;
}
void push(int x) {
	stk[++tt] = x;
}

10.模拟队列

const int N = 1e5 + 10;
int ll = 0, rr = 1,a[N];
void push(int x) {
	a[rr++] = x;
}
void pop() {
	ll++;
}
void empty() {
	if (rr - ll == 1)cout << "YES" << endl;
	else cout << "NO" << endl;
}
void query() {
	cout << a[ll + 1] << endl;
}

11.单调栈

#include<iostream>
using namespace std;
const int N=1e5+5;
int a[N];
int main(){
    int n;
    cin>>n;
    int tt=0;
    for(int i=0;i<n;i++){
        int x;
        scanf("%d",&x);
        while(tt&&a[tt]>=x)tt--;
        if(tt)cout<<a[tt]<<" ";
        else cout<<"-1"<<" ";
        a[++tt]=x;
    }
    return 0;
}

12.滑动窗口

#include<iostream>
using namespace std;
const int N=1e6+10;
int a[N],b[N],hh,tt=-1;
int main(){
    int n,k;
    scanf("%d%d",&n,&k);
    for(int i=0;i<n;i++){
        scanf("%d",&a[i]);
        if(i-k+1>b[hh])++hh;
        while(hh<=tt&&a[i]<=a[b[tt]])--tt;
        b[++tt]=i;
        if(i+1>=k)printf("%d ",a[b[hh]]);
    }
    cout<<endl;
    hh=0,tt=-1;
        for(int i=0;i<n;i++){
        if(i-k+1>b[hh])++hh;
        while(hh<=tt&&a[i]>=a[b[tt]])--tt;
        b[++tt]=i;
        if(i+1>=k)printf("%d ",a[b[hh]]);
    }
}

12.kmp字符串

#include<iostream>
using namespace std;
const int N=1e5+10,M=1e6+10;
char a[N],b[M];
int ne[N];
int main(){
    int n,m;
    cin>>n>>a+1>>m>>b+1;
    for(int i=2,j=0;i<=n;i++){
        while(j&&a[i]!=a[j+1])j=ne[j];
        if(a[i]==a[j+1])j++;
        ne[i]=j;
    }
    for(int i=1,j=0;i<=m;i++){
        while(j&&b[i]!=a[j+1])j=ne[j];
        if(b[i]==a[j+1])j++;
        if(j==n){
            cout<<i-n<<' ';
            j=ne[j];
        }
    }
}

13.Trie字符串统计

int son[N][26],cnt[N],idx=0;
char str[N];
void insert(char*str){
    int p=0;
    for(int i=0;str[i];i++){
        int u=str[i]-'a';
        if(!son[p][u])son[p][u]=++idx;
        p=son[p][u];
    }
    cnt[p]++;
    
}
int query(char *str){
    int p=0;
    for(int i=0;str[i];i++){
        int u=str[i]-'a';
        if(!son[p][u])return 0;
        else p=son[p][u];
    }
    return cnt[p];
}

14.最大异或对

x>>i&1;  //取X的第i位的二进制数是什么
#include<iostream>
#include<algorithm>
using namespace std;
const int N =1e5+10, M = N * 31;
int n, a[N], son[M][2],idx;
void insert(int x) {
    int p=0;
    for(int i=30;i>=0;i--){
        int u=x>>i&1;
        if(!son[p][u])son[p][u]=++idx;
        p=son[p][u];
    }
}
int search(int x) {
	int p = 0, res = 0;
	for (int i = 30; i >= 0; i--) {
		int u = x >> i & 1;
		if (son[p][!u]) {
			p = son[p][!u];
			res = res * 2 + 1;
		}
		else {
			p = son[p][u];
			res = res * 2 + 0;
		}
	}
	return res;
}
int main() {
	cin >> n;
	int maxanswer = -1;
	for (int i = 0; i < n; i++) {
		scanf("%d", &a[i]);
		insert(a[i]);
		maxanswer = max(maxanswer, search(a[i]));
	}
	cout << maxanswer << endl;
}

15.并查集

1.将两个集合合并

2.查询两个元素是否在一个集合当中

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

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

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

16.堆

STL中的堆:头文件:#include<queue>

大根堆:priority_queue<int>q;

小根堆:priority_queue<int,vector<int>,greater<int>>q;

q.top()//取得堆顶元素,并不会弹出
q.pop()//弹出堆顶元素
q.push()//往堆里面插入一个元素
q.empty()//查询堆是否为空,为空则返回1否则返回0
q.size()//查询堆内元素数量
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 1e5 + 10;
int h[N],num;
void down(int x) {
	int t = x;
	if (2 * x <= num && h[t] >h[x * 2])t = x * 2;
	if (2 * x +1<= num && h[t] >h[x * 2+1])t = x * 2+1;
	if (t != x) {
		swap(h[t], h[x]);
		down(t);
	}
}
int main() {
	int n, m;
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= n; i++)scanf("%d", &h[i]);
	num = n;
	for (int i = n / 2; i; i--)down(i);
	while (m--) {
		printf("%d ", h[1]);
		h[1] = h[num];
		num--;
		down(1);
	}
}
#include<string.h>
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 1e5 + 10;
int h[N],ph[N],hp[N],num;
void heap_swap(int a,int b){
    swap(ph[hp[a]],ph[hp[b]]);
    swap(hp[a],hp[b]);
    swap(h[a],h[b]);
    
}
void down(int x) {
	int t = x;
	if (2 * x <= num && h[t] >h[x * 2])t = x * 2;
	if (2 * x +1<= num && h[t] >h[x * 2+1])t = x * 2+1;
	if (t != x) {
		heap_swap(t,x);
		down(t);
	}
}
void up(int x){
    while(x/2&&h[x/2]>h[x]){
        heap_swap(x/2,x);
        x/=2;
        
    }
    
}
int main() {
	int n, m=0;
	scanf("%d",&n);
	int k,x;
	while(n--){
	    char op[10];
	    scanf("%s",op);
	    if(!strcmp(op,"I")){
	        scanf("%d",&x);
	        num++;m++;
	        ph[m]=num,hp[num]=m;
	        h[num]=x;
	        up(num);
	    }
	    else if(!strcmp(op,"PM")){
	        printf("%d\n",h[1]);
	    }
	    else if(!strcmp(op,"DM")){
	       heap_swap(1,num);
	        num--;
	        down(1);
	    }
	    else if(!strcmp(op,"D")){
	        scanf("%d",&k);
	        k=ph[k];
	        heap_swap(k,num);
	        num--;
	        down(k),up(k);
	    }
	    else{
	        scanf("%d%d",&k,&x);
	        k=ph[k];
	        h[k]=x;
	        down(k),up(k);
	    }
	    
	}

}

17.哈希表

维护一个集合,支持如下几种操作:

  1. I x,插入一个数 x;
  2. Q x,询问数 x 是否在集合中出现过;
//拉链法
#include <cstring>
#include <iostream>

using namespace std;

const int N = 1e5 + 3;  // 取大于1e5的第一个质数,取质数冲突的概率最小 可以百度

//* 开一个槽 h
int h[N], e[N], ne[N], idx;  //邻接表

void insert(int x) {
    // c++中如果是负数 那他取模也是负的 所以 加N 再 %N 就一定是一个正数
    int k = (x % N + N) % N;
    e[idx] = x;
    ne[idx] = h[k];
    h[k] = idx++;
}

bool find(int x) {
    //用上面同样的 Hash函数 讲x映射到 从 0-1e5 之间的数
    int k = (x % N + N) % N;
    for (int i = h[k]; i != -1; i = ne[i]) {
        if (e[i] == x) {
            return true;
        }
    }
    return false;
}

int n;

int main() {
    cin >> n;

    memset(h, -1, sizeof h);  //将槽先清空 空指针一般用 -1 来表示

    while (n--) {
        string op;
        int x;
        cin >> op >> x;
        if (op == "I") {
            insert(x);
        } else {
            if (find(x)) {
                puts("Yes");
            } else {
                puts("No");
            }
        }
    }
    return 0;
}
//开放寻址法
#include <cstring>
#include <iostream>

using namespace std;

//开放寻址法一般开 数据范围的 2~3倍, 这样大概率就没有冲突了
const int N = 2e5 + 3;        //大于数据范围的第一个质数
const int null = 0x3f3f3f3f;  //规定空指针为 null 0x3f3f3f3f

int h[N];

int find(int x) {
    int t = (x % N + N) % N;
    while (h[t] != null && h[t] != x) {
        t++;
        if (t == N) {
            t = 0;
        }
    }
    return t;  //如果这个位置是空的, 则返回的是他应该存储的位置
}

int n;

int main() {
    cin >> n;

    memset(h, 0x3f, sizeof h);  //规定空指针为 0x3f3f3f3f

    while (n--) {
        string op;
        int x;
        cin >> op >> x;
        if (op == "I") {
            h[find(x)] = x;
        } else {
            if (h[find(x)] == null) {
                puts("No");
            } else {
                puts("Yes");
            }
        }
    }
    return 0;
}

        给定一个长度为 n 的字符串,再给定 m 个询问,每个询问包含四个整数 l1,r1,l2,r2,请你判断 [l1,r1] 和 [l2,r2]这两个区间所包含的字符串子串是否完全相同。

字符串中只包含大小写英文字母和数字。

#include<iostream>

using namespace std;
typedef unsigned long long ULL;
const int N=1e5+10,P=131;
int n,m;
char str[N];
ULL h[N],p[N];
ULL get(int l,int r){
    return h[r]-h[l-1]*p[r-l+1];
}
int main(){
    scanf("%d%d%s",&n,&m,str+1);
    p[0]=1;
    for(int i=1;i<=n;i++){
        p[i]=p[i-1]*P;
        h[i]=h[i-1]*P+str[i];
    }
    while(m--){
        int l1,r1,l2,r2;
        scanf("%d%d%d%d",&l1,&r1,&l2,&r2);
        if(get(l1,r1)==get(l2,r2))puts("Yes");
        else puts("No");
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值