Acwing算法基础

与普通函数区别:1.多了个template<class T>;2.某些确定类型变不确定类型T

一:引子:

#include<iostream>
using namespace std;
template<typename T>
T Max(T a, T b)
{
	return a > b ? a : b;
}
int main()
{
	int x, y;
	double a, b;
	cin >> x >> y >> a >> b;
	cout << Max(a, b) << "\n" << Max(x, y);
}

结果: 

回文数判断

1.回文数

1.回文数判断模板
模板:
#include <iostream>
#include <algorithm>
using namespace std;
template <typename T, size_t N>//size_t很多时候等价于int,但更安全,不会溢出
bool is_symmetric(T(&a)[N]) {//既可以接收数组,也可以接收字符串且传递了长度
	size_t i=0, j= N - 1;
	while (i <= j) {
		if (a[i] != a[j])
			return false;
		++i, --j;
	}
	return true;
} 


测试:
int main() {
	int a[]{ 1, 2, 3, 4, 5, 4, 3, 2, 1 };
	
		cout << is_symmetric(a) << endl; //1
	cout << is_symmetric("aaaaaaaaaaaaaaaaa") << endl; //0
}

快速排序(双指针)

—分治思想

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=1e6+10;
int n;
int q[N];

//****************************************
void quick_sort(int q[],int l,int r)
{
	if(l>=r)return;
    //确定分界点
	int x=q[l],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_sort(q,l,j);
	quick_sort(q,j+1,r);
}

//********************************************
int main()
{
	scanf("%d",&n);
	
	for(int i=0;i<n;i++)scanf("%d",&q[i]);
	
	quick_sort(q,0,n-1);
	
	for(int i=0;i<n;i++)printf("%d ",q[i]);
	
	return 0;
}

拓展1: 快速选择算法

#include<iostream>
#include<algorithm>
using namespace std;
const int N = 1e5 + 10;
int q[N];
int n, k;

int quick_sort(int l, int r, int k)
{
	if (l == r)return q[l];
		int i = l - 1, j = r + 1, x = q[l];
	while (i < j)
	{
		while (q[++i] < x);
		while (q[--j] > x);
		if (i < j)swap(q[i], q[j]);
	}
	int s1 = j - l + 1;//左半边长度

    //确定在哪边之后对该部分递归快排即可,另一边不用排了(剪枝!!!)
	if (k <= s1)return quick_sort(l, j, k);
	else return quick_sort(j + 1, r, k - s1);
}

int main()
{
	cin >> n >> k;
	for (int i = 0; i < n; i++)cin >> q[i];

	cout<<quick_sort(0, n - 1, k);
	return 0;
}

 归并排序(合二为一)

—分治思想

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=1e6+10;
int n;
int q[N],temp[N];

//******************************************************************
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])temp[k++]=q[i++];
		else temp[k++]=q[j++];
	}
	while(i<=mid)temp[k++]=q[i++];
	while(j<=r)temp[k++]=q[j++];
	
	for(i=l,j=0;i<=r;i++,j++)q[i]=temp[j];
}
//******************************************************************

int main()
{
	scanf("%d",&n);
	
	for(int i=0;i<n;i++)scanf("%d",&q[i]);
	
	merge_sort(q,0,n-1);
	
	for(int i=0;i<n;i++)printf("%d ",q[i]);
	
	return 0;
}
拓展1:求逆序对数量

#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;
const int N = 1e5 + 10;
int q[N];

int merge_sort(int l,int r)
{
	if(l==r)return 0;
	int tmp[N];
	int mid=l+r>>1;
	LL res=merge_sort(l,mid)+merge_sort(mid+1,r);
	
	//归并过程
	int i=l,j=mid+1,k=0;
	while(i<=mid&&j<=r){
		if(q[i]<=q[j])tmp[k++]=q[i++];
		else 
		{
			tmp[k++]=q[j++];
			res+=mid-i+1;//在排序的过程同时求逆序对数量
		}
	}
	
	//扫尾
	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];
	
	return res;
}

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

5
5 4 1 2 3

--------------------------------
Process exited after 30.19 seconds with return value 3221225725
请按任意键继续. . .

二分(整数)

高精度

加法

#include<iostream>
#include<vector>
#include<cstring>
using namespace std;
const int N=1e6+10;


//******************************************************
vector<int> add(vector<int> &A,vector<int> &B)
{
	//C=A+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];
		int c=t%10;
		C.push_back(c);
		t/=10;
	}
	
	//最高位
	if(t)C.push_back(1);
	
	return C;
}
//******************************************************

int main()
{
	string a,b;
	vector<int>A,B;
	
	cin>>a>>b;//a="123456"
	for(int i=a.size()-1;i>=0;i--)A.push_back(a[i]-'0');//A=[6,5,4,3,2,1]
	for(int i=b.size()-1;i>=0;i--)B.push_back(b[i]-'0');
	
	auto C=add(A,B);
	for(int i=C.size()-1;i>=0;i--)cout<<C[i];
	
	return 0;
}

23
39
62
--------------------------------
Process exited after 7.258 seconds with return value 0
请按任意键继续. . .

减法

#include<iostream>
#include<vector>
#include<cstring>
using namespace std;
const int N = 1e6 + 10;

//******************************************************
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)
{
	//C=A-B
	vector<int>C;
	int t = 0;//借位

	for (int i = 0; i < A.size(); i++)
	{
		if (i < B.size())
		{
			if (A[i] - B[i] - t < 0)
			{
				C.push_back(10 + A[i] - B[i] - t);
				t = 1;
			}
			else
			{
				C.push_back(A[i] - B[i] - t);
				t = 0;
			}
		}
		else
		{
			C.push_back(A[i] - t);
			t = 0;
		}
	}
	while (C.size()>1&&C[C.size() - 1] == 0)C.pop_back();
	return C;
}
//******************************************************

int main()
{
	string a, b;
	vector<int>A, B;

	cin >> a >> b;//a="123456"

	//倒着存储
	for (int i = a.size() - 1; i >= 0; i--)A.push_back(a[i] - '0');//A=[6,5,4,3,2,1]
	for (int i = b.size() - 1; i >= 0; i--)B.push_back(b[i] - '0');

	//确保是大减小
	if (cmp(A, B))
	{
		auto C = sub(A, B);
		for (int i = C.size() - 1; i >= 0; i--)cout << C[i];//易漏,两条件
	}
	else
	{
		auto C = sub(B, A);
		cout << '-';
		for (int i = C.size() - 1; i >= 0; i--)cout << C[i];
	}


	return 0;
}

22
33
-11
--------------------------------
Process exited after 5.188 seconds with return value 0
请按任意键继续. . .

乘法

//一长一短相乘(高精度*低精度)
#include<iostream>
#include<vector>
#include<cstring>
using namespace std;
const int N = 1e6 + 10;

//******************************************************

vector<int> mul(vector<int>& A, int b)
{
	//C=A*b
	vector<int>C;
	int t = 0;//进位

	for (int i = 0; i < A.size(); i++)
	{
		C.push_back((A[i] * b + t) % 10);
		t = (A[i] * b + t) / 10;
	}
	//最后进位
	while (t)
	{
		C.push_back(t % 10);
		t /= 10;
	}
	return C;
}
//******************************************************

int main()
{
	string a;
	int b;
	vector<int>A;

	cin >> a >> b;//a="123456"

	//倒着存储
	for (int i = a.size() - 1; i >= 0; i--)A.push_back(a[i] - '0');//A=[6,5,4,3,2,1]
	
	auto C = mul(A, b);
	for (int i = C.size() - 1; i >= 0; i--)cout << C[i];
	
	return 0;
}

1111
9999
11108889
D:\A.codefield\VS\Project2\x64\Debug\Project2.exe (进程 5556)已退出,代码为 0。
按任意键关闭此窗口. . .

除法

//一长一短相除(高精度/低精度)
#include<iostream>
#include<vector>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 1e6 + 10;

//******************************************************

vector<int> div(vector<int>& A, int b, int& r)
{
	//C=A/b
	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());
	//防止出现123/123=001
	while (C.size() > 1 && C.back() == 0)C.pop_back();
	return C;
}
//******************************************************

int main()
{
	string a;//被除数
	int b;//除数
	int r = 0;//余数
	vector<int>A;

	cin >> a >> b;//a="123456"

	/*本应该正着存储(不存在进位或者借位问题,不需要倒着存储)
		但是为了统一格式(加减乘都是倒着存储),这里也导致存储*/
	for (int i = a.size()-1; i >= 0; i--)A.push_back(a[i] - '0');//A=[6,5,4,3,2,1]


	auto C = div(A, b, r);
	cout << "商=";
	for (int i = C.size() - 1; i >= 0; i--)cout << C[i];
	cout << endl << "余数=";
	cout << r;

	return 0;
}

123
11
商=11
余数=2
--------------------------------
Process exited after 3.994 seconds with return value 0
请按任意键继续. . .

双指针 

 

eg1 双指针维护不重复队列

//双指针维护不重复队列
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=100010;
int a[N],s[N];//a存储输入数据,s模拟包含不重复元素的队列(s[i]表示栈内i的数量)

int main()
{
	int n,res=0;
	cin>>n;
	for(int i=0;i<n;i++)cin>>a[i];
	
    //枚举窗口右端点j
	for(int j=0,i=0;j<n;j++){
		s[a[j]]++;//a[j]进栈
		while(s[a[j]]>1)//如果a[j]进队列后队列内元素重复那只可能是新加入的a[j]重复
        {
            i++;
			s[a[i]]--;//弹出队列
		}
		res=max(res,j-i+1);
	}
	cout<<res;
	return 0;
}

离散化 

 eg1

 

#include<iostream>
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
const int N = 300010;//n+2m
typedef pair<int,int> PII;
int n, m,a[N],s[N];
vector<int>alls;
vector<PII>add, query;

//找到x离散后的位置
//********************************************
int find(int x)
{
	int l = 1, r = alls.size();

	while (l < r) {
		int mid = l + r >> 1;
		if (alls[mid] >= x)r = mid;
		else l = mid + 1;
	}
	return r;
}
//********************************************
int main()
{
	cin >> n >> m;
	//输入插入
	for (int i = 0; i < n; i++) {
		int x, c;
		scanf("%d%d", &x, &c);
		add.push_back({ x,c });
		alls.push_back(x);
	}
	//输入查询
	for (int i = 0; i < m; i++) {
		int l, r;
		cin >> l >> r;
		alls.push_back(l); alls.push_back(r);
		query.push_back({ l,r });
	}

	//去重
	//************************************************************
	sort(alls.begin(), alls.end());
	alls.erase(unique(alls.begin(), alls.end()), alls.end());
	//************************************************************
	//插入
	for (auto item : add) {
		int x = find(item.first);
		a[x] += 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;
}

数据结构

常用代码模板2——数据结构 - AcWing

单链表 

// head存储链表头,e[]存储节点的值,ne[]存储节点的next指针,idx表示当前用到了哪个节点
int head, e[N], ne[N], idx;

// 初始化
void init()
{
    head = -1;
    idx = 0;
}

// 在链表头插入一个数a
void insert(int a)
{
    e[idx] = a, ne[idx] = head, head = idx ++ ;
}

// 将头结点删除,需要保证头结点存在
void remove()
{
    head = ne[head];
}
eg1

#include<iostream>
using namespace std;
const int N = 100010;
int head, e[N], ne[N], idx;
int n;
void init()
{
    head = -1;
    idx = 0;//当前处理位置下标
}
void add_head(int x)
{
    e[idx] = x, ne[idx] = head, head = idx++;
}
void add_k(int k, int x)
{
    e[idx] = x;
    ne[idx] = ne[k];
    ne[k] = idx++;
}

void remove(int k)
{
    ne[k] = ne[ne[k]];
}

int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    init();
    cin >> n;
    while (n--) {
        char ch;
            int k, x;
        cin >> ch;
        if (ch == 'H') {
            cin >> x;
            add_head(x);
        }
        else if (ch == 'I') {
            cin >> k >> x;
            add_k(k - 1, x);//因为下标是从0开始算的,所以第k个插入的点的下标为k-1
        }
        else if (ch == 'D') {
            cin >> k;
            if (k == 0)head = ne[head];//特判头结点
            else remove(k - 1);
        }
    }
    for (int i = head; i != -1; i = ne[i]) {
        cout << e[i] << " ";
    }
    return 0;
}

 

 双链表

// e[]表示节点的值,l[]表示节点的左指针,r[]表示节点的右指针,idx表示当前用到了哪个节点
int e[N], l[N], r[N], idx;

// 初始化
void init()
{
    //0是左端点,1是右端点
    r[0] = 1, l[1] = 0;
    idx = 2;
}

// 在节点a的右边插入一个数x
void insert(int a, int x)
{
    e[idx] = x;
    l[idx] = a, r[idx] = r[a];
    l[r[a]] = idx, r[a] = idx ++ ;
}

// 删除节点a
void remove(int a)
{
    l[r[a]] = l[a];
    r[l[a]] = r[a];
}

// tt表示栈顶
int stk[N], tt = 0;

// 向栈顶插入一个数
stk[ ++ tt] = x;

// 从栈顶弹出一个数
tt -- ;

// 栈顶的值
stk[tt];

// 判断栈是否为空,如果 tt > 0,则表示不为空
if (tt > 0)
{

}

 

队列

单调栈

--------- >左边比当前小且最近的树

 

//数组模拟单调栈
#include<iostream>
using namespace std;
const int N = 100010;
int n;
int stk[N], tt;//tt表示栈顶下标,当tt等于0时表示栈为空
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    cin >> n;
    int x;
    for (int i = 0; i < n; i++) {
        cin >> x;
        while (tt && stk[tt] >= x)tt--;//弹出
        if (tt)cout << stk[tt] << " ";
        else cout << "-1 ";
        stk[++tt] = x;//入栈
    }
    return 0;
}

//STL
#include<iostream>
#include<stack>
using namespace std;
const int N = 100010;
int n;
stack<int>stk;
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    cin >> n;
    int x;
    for (int i = 0; i < n; i++) {
        cin >> x;
        while (stk.size() && stk.top() >= x)stk.pop();
        if (stk.size())cout << stk.top() << " ";
        else cout << "-1" << " ";
        stk.push(x);
    }
    return 0;
}

 单调队列

------滑动窗口的最大值最小值

 

//数组模拟单调队列
#include<iostream>
using namespace std;
const int N = 1e6+10;
int a[N],que[N];//a存储值大小,que存储值下标
int n,k;
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    cin>>n>>k;
    for(int i=0;i<n;i++)cin>>a[i];
    
    int hh=0,tt=-1;
    
    //求窗口内最小
    for(int i=0;i<n;i++){//枚举窗口右端
        //判断对头是否已经滑出窗口
        if(hh<=tt&&i-k+1>que[hh])hh++;//弹出
        
        while(hh<=tt&&a[que[tt]]>=a[i])tt--;//使得队列单调递增,!!!从队尾开始踢
        que[++tt]=i;//入队
        if(i>=k-1)cout<<a[que[hh]]<<" ";
    }
    cout<<"\n";
    //求敞口内最大(与求滑动窗口最小值几乎一样)
    
    hh=0,tt=-1;//!!!!!!!!!!1不能漏!!!!
    
    for(int i=0;i<n;i++){
        if(hh<=tt&&i-k+1>que[hh])hh++;
        while(hh<=tt&&a[que[tt]]<=a[i])tt--;//这里符合不同
        que[++tt]=i;
        if(i>=k-1)cout<<a[que[hh]]<<" ";
    }
    return 0;
}
//STL(有一个数据过不去不知道为啥)
#include<iostream>
#include<cstring>
#include<deque>
using namespace std;
const int N = 1e6 + 10;
int a[N];//a存储值大小
deque<int>q;//队列存储值而非下标
int n, k;
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    cin >> n >> k;
    for (int i = 0; i < n; i++)cin >> a[i];
    //求窗口内最小值
    for (int i = 0; i < n; i++) {
        if (!q.empty() && i-k>=0&&q.front()==a[i-k])q.pop_front();//非空且窗口越界
        while (!q.empty() && a[i] <= q.back())q.pop_back();//只需维护窗口最小即可
        q.push_back(a[i]);
        if (i - k + 1 >= 0)cout << q.front() << " ";//达到窗口大小才输出
    }
    cout << "\n";
    q.clear();
    //求窗口内最大值
    for (int i = 0; i < n; i++) {
        if (!q.empty() && i-k>=0&&q.front()==a[i-k])q.pop_front();//非空且窗口越界
        while (!q.empty() && a[i] >= q.back())q.pop_back();//只需维护窗口最小即可
        q.push_back(a[i]);
        if (i - k + 1 >= 0)cout << q.front() << " ";//达到窗口大小才输出
    }
    cout<<"\n";
    return 0;
}

KMP

eg1

//暴力
#include<iostream>
#include<cstring>
using namespace std;
const int N=1010;
int n,m;
string s,p;
int cnt;
int ne[N];
bool check(int st)
{
    for(int i=0;i<m;i++){
        if(p[i]!=s[st++])return false;
    }
    return true;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);
    cin>>n>>s>>m>>p;
    int st,i,j;
    for(int st=0;st<n;st++){
        if(check(st))cout<<st<<" ";
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hz2.0

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值