常用算法代码模板及代码技巧

参考《AcWing算法基础课》、《AcWing算法提高课》等课程的思路,并结合日常刷题实践,我将常用的算法模板进行了系统整理。

现分享如下,既为方便自己查阅,也希望能为大家的学习提供一份参考。


基础算法

快速排序

模板

// do-while版本
void quick_sort(int q[], int l, int r)
{
    if (l>=r) return;
    int rnd_idx = rand() % (r-l+1)+l;
    swap(q[l], q[rnd_idx]);
    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);
}

// while版本
void quick_sort(int q[], int l, int r)
{
    if (l>=r) return;
    int rnd_idx = rand() % (r-l+1)+l;
    swap(q[l], q[rnd_idx]);
    int x=q[l], i=l-1, j=r+1;
    while (i<j) 
	{
        while (q[++i]<x);
		while (q[--j]>x);
        if (i<j) swap(q[i], q[j]);
    }
    quick_sort(q, l, j);
    quick_sort(q, j+1, r);
}

题解:AcWing 785 快速排序

归并算法

模板

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

题解:AcWing 787 归并排序

整数二分

模板

bool check(int x) {/* ... */} // 检查x是否满足某种性质

// 区间[l, r]被划分成[l, mid]和[mid + 1, r]时使用:
int bsearch_1(int l, int r)
{
    while (l < r)
    {
        int mid = l + r >> 1;
        if (check(mid)) r = mid;    // check()判断mid是否满足性质
        else l = mid + 1;
    }
    return l;
}
// 区间[l, r]被划分成[l, mid - 1]和[mid, r]时使用:
int bsearch_2(int l, int r)
{
    while (l < r)
    {
        int mid = l + r + 1 >> 1;  //当l=mid时,一定要l+r+1
        if (check(mid)) l = mid;
        else r = mid - 1;
    }
    return l;
}

题解:AcWing 789 数的范围

浮点数二分

模板

bool check(double x) {/* ... */} // 检查x是否满足某种性质

double bsearch_3(double l, double r)
{
    double eps = 1e-6;   // eps 表示精度,取决于题目对精度的要求,需要比预留的小数位+2
    while (r - l > eps)
    {
        double mid = (l + r) / 2;
        if (check(mid)) r = mid;
        else l = mid;
    }
    return l;
}

题解:AcWing 790 数的三次方根

高精度加法

模板

//高精度数输入
void s2BIG(string s, int a[])
{
    a[0] = s.size();
    for (int i=1; i<=a[0]; i++)
        a[i] = s[a[0]-i] - '0';
}
// 高精度数输出
void printBIG(int a[])
{
    for (int i=a[0]; i>=1; i--)
        cout << a[i];
    cout << endl;
}
//低精度转高精度
void i2BIG(int n, int a[])
{
	while (n>0)
	{
		a[++a[0]] = n % 10;
		n /= 10;
	}
	if (a[0] == 0) a[0] = 1;
}
//高精加
void addBIG(int a[], int b[], int c[])
{
	c[0] = max(a[0], b[0]);
	int u = 0;  // u存储低位向高位的进位
	for (int i=1; i<=c[0]; i++)
	{
		int t = a[i] + b[i] + u;
		c[i] = t % 10;
		u = t / 10;
	}
	if (u>0) c[++c[0]] = u;
}
	

题解:AcWing 791 高精度加法

高精度减法

模板

//高精比较
bool cmpBIG(int a[], int b[])
{ // 判断高精度数字a是否小于高精度数字b
	if (a[0] != b[0]) return a[0]<b[0];
	for (int i=a[0]; i>=1; i--)
		if (a[i] != b[i])
			return a[i] < b[i];
	return false;
}

//高精减
void subBIG(int a[], int b[], int c[])
{
	c[0] = max(a[0], b[0]);
	int u = 0;
	for (int i=1; i<=c[0]; i++)
	{
		int t = a[i]-b[i]-u;
		if (t<0) 
		{
			u = 1;
			c[i] = t + 10;
		}
		else
		{
			u = 0;
			c[i] = t;
		}
	}
	while (c[c[0]] == 0 && c[0]>1) c[0]--;
}

题解:AcWing 792 高精度减法

高精度乘法

模板

//高精乘(高精*低精)
void mulBIG(int a[], int b, int c[])
{
	c[0] = a[0];
	int u = 0;

	for (int i=1; i<=c[0]; i++)
	{
		int t = a[i] * b + u;
		c[i] = t % 10;
		u = t / 10;
	}

	while (u>0) 
	{
		c[++c[0]] = u % 10;
		u /= 10;
	}
}
//高精乘(高精*高精)
void mulBIG2(int a[], int b[], int c[])
{
    c[0] = a[0] + b[0];
    int u = 0;
    for (int j=1; j<=b[0]; j++)
    {
        int u = 0;
      
        for (int i=1; i<=a[0]; i++)
        {
            int t = a[i]*b[j] + c[i+j-1] + u;
            c[i+j-1] = t % 10;
            u = t / 10;
        }
        if (u>0)
            c[a[0]+j] += u;      
    }
    while (c[0]>1 && c[c[0]]==0)
    {
        c[0]--;
    }
  
}

题解:AcWing 793 高精度乘法

高精度除法

模板

//高精度除法
void divBIG1(int a[], int b, int c[])
{ // 将高精度数字a[]与低精度数字b相除,所得的商存入高精度数组c[]中
	c[0] = a[0];
	int r = 0;

	for(int i = c[0]; i >= 1; i--)
	{
		int t = r * 10 + a[i];
		c[i] = t / b;
		r = t % b;
	}

	while(c[c[0]] == 0 && c[0] > 1) c[0]--;
}

void divBIG2(int a[], int b[], int c[])
{ // 将高精度数字a[]与高精度数字b[]相除,所得的商存入高精度数组c[]中
	// int temp[1005] = {0}; // 临时数组
	// int count[1005] = {0}; // 计数数组
	c[0] = 1; // 初始商为0
	c[1] = 0;

	// 特殊情况处理
	if(cmpBIG(a, b))
	{ // 如果a < b,直接返回0
		c[0] = 1;
		c[1] = 0;
		return;
	}

	// 计算商的位数
	c[0] = a[0] - b[0] + 1;
	for(int i = 1; i <= c[0]; i++) c[i] = 0;

	// 模拟竖式除法
	for(int i = c[0]; i >= 1; i--)
	{
		// 调整除数位数
		int tempB[1005] = {0};
		tempB[0] = b[0] + i - 1;
		for(int j = 1; j <= b[0]; j++)
			tempB[j+i-1] = b[j];
		
		// 试商
		while(!cmpBIG(a, tempB))
		{
			// a = a - tempB
			subBIG(a, tempB, a);
		
			c[i]++; // 商对应位加1
		
			// 处理进位
			int j = i;
			while(c[j] > 9)
			{
				c[j+1] += c[j] / 10;
				c[j] %= 10;
				j++;
				if(j > c[0]) c[0] = j;
			}
		}
	}

	// 去除前导零
	while(c[c[0]] == 0 && c[0] > 1) c[0]--;
}

题解:AcWing 794 高精度除法

数据结构

单调队列

模板

struct Node
{
    int v, idx; 
};
deque<Node> dq;  


for (int i = 1; i <= n; i++)  // 遍历数组
{
    while (!dq.empty() && dq.front().idx <= i - k)
        dq.pop_front();
    // 维护minq队列:保持队列单调递增
	// 如果修改为dq.back().v <= a[i],则维护maxq队列:保持队列单调递减
    while (!dq.empty() && dq.back().v >= a[i])
        dq.pop_back();
    dq.push_back({a[i], i});  // dq.front().v为最小值

    // 按照题目要求输出最小值、最大值等
}

题解:AcWing 154 滑动窗口

动态规划

线性DP

模板1

// 状态表示
dp[i]表示以第i项结尾的所有子段和的最大值
// 初始状态
dp[0] = 0
// 状态转移
dp[i] = a[i]  // 以第i项作为新子段
dp[i] = dp[i-1] + a[i]  // 将第i项接在前面的子段尾部
// 结果
max{dp[i]}

题解:洛谷 P1115 最大子段和

题解:删数最大子段和

题解:最大子段和3

模板2

// 状态表示
dp[i]表示前i个数字共有多少种翻译方法
// 初始状态
dp[0] = 1, dp[1] = 1
// 状态转移
dp[i] = dp[i-1] + dp[i-2]  // if (s[i-1]=='1' || s[i-1]=='2' && s[i]<='5',s[i]和s[i-1]合并翻译,s[i]单独翻译 
dp[i] = dp[i-1]  // else s[i]只能单独翻译
// 结果
dp[n]

题解:解码方法

题解:单词解密

模板3

// 状态表示
dp[i]表示前i个数字组成的数列共有多少种划分方法
// 初始状态
dp[0] = 1
// 状态转移
dp[i] = dp[i-1]  // a[i]单独一组; a[i]<=s; sum[i]-sum[i-1]<=s;
dp[i] = dp[i-2]  // a[i-1]和a[i]组成一组; a[i-1]+a[i]<=s; sum[i]-sum[i-2]<=s;
dp[i] = dp[i-3]  // a[i-2]、a[i-1]和a[i]组成一组; a[i-2]+a[i-1]+a[i]<=s; sum[i]-sum[i-3]<=s;
...
dp[i] = dp[k]  // a[k+1]、...、a[i-1]和a[i]组成一组; a[k+1]+...+a[i-1]+a[i]<=s; sum[i]-sum[k]<=s;
...
dp[i] = dp[0]  // a[1]、a[2]、...、a[i-1]和a[i]组成一组; a[1]+a[2]+...+a[i-1]+a[i]<=s; sum[i]-sum[0]<=s;
// 结果
dp[n]

题解:数列划分

模板4

// 状态表示
dp[i]表示前i个字母组成的字符串可以被划分成的最少的单词数
// 初始状态
memset(dp, 0x3f, sizeof(dp)); dp[0] = 0;
// 状态转移
dp[i] = dp[0] + 1;  // s[1]~s[i]是字典中的某个单词
dp[i] = dp[1] + 1;  // s[2]~s[i]是字典中的某个单词
...
dp[i] = dp[k] + 1;  // s[k+1]~s[i]是字典中的某个单词
...
dp[i] = dp[i-1] + 1;  // s[i]是字典中的某个单词
// 结果
dp[m+1]

题解:单词的划分

最长上升子序列

模板1

// 状态表示
dp[i]表示以a[i]为结尾的最长上升子序列的长度
// 初始状态
dp[i] = 1 (1<=i<=n)
// 状态转移
dp[i] = dp[1] + 1;  a[1]<a[i]
dp[i] = dp[2] + 1;  a[2]<a[i]
...
dp[i] = dp[j] + 1;  a[j]<a[i]
...
dp[i] = dp[i-1] + 1;  a[i-1]<a[i]

dp[i] = max(dp[i], dp[j] + 1);  (1<=j<=i-1, a[j]<a[i])
// 结果
max{dp[i]}

// 其他变形
最长下降子序列:a[j]>a[i]
最长不下降子序列:a[j]<=a[i]
最长不上升子序列:a[j]>=a[i]

题解:AcWing 895 最长上升子序列

模板2

// 状态表示
dp[i]表示以a[i]为结尾的上升子序列的和的最大值
// 初始状态
dp[i] = a[i] (1<=i<=n)
// 状态转移
dp[i] = max(dp[i], dp[j] + a[i]);  (1<=j<=i-1, a[j]<a[i])
// 结果
max{dp[i]}

题解:AcWing 1016 最大上升子序列和

最长上升子序列二分优化

模板

// 最长上升子序列
len = 0;
for (int i=1; i<=n; i++)
{
	if (a[i]>b[len])
	{
		b[++len] = a[i];
		dp[i] = len;
	}
	else 
	{
		int m = lower_bound(b+1, b+len+1, a[i]) - b;
		b[m] = a[i];
		dp[i] = m;
	}
}

// 最长不下降子序列
len = 0;
for (int i=1; i<=n; i++)
{
	if (a[i]>b[len])
	{
		b[++len] = a[i];
		dp[i] = len;
	}
	else 
	{
		int m = upper_bound(b+1, b+len+1, a[i]) - b;
		b[m] = a[i];
		dp[i] = m;
	}
}

题解:AcWing 896 最长上升子序列 II

题解:字符串改造

01背包

模板1

// 最值型01背包
// 朴素解法
for (int i=1; i<=n; i++) 
{
	for (int j=0; j<=m; j++) 
	{
		f[i][j] = f[i-1][j];
		if (j>=v[i]) 
			f[i][j] = max(f[i][j], f[i-1][j-v[i]]+w[i]);
	}
}
// 一维数组优化
for (int i=1; i<=n; i++) 
	for (int j=m; j>=v[i]; j--)
        f[j] = max(f[j], f[j-v[i]]+w[i]);

题解:AcWing 2 01背包问题

模板2

// 布尔型01背包
dp[j] |= dp[j-w[i]]

题解:砝码称重

模板3

// 计数型01背包
dp[j] += dp[j-w[i]]

题解:AcWing 1365 子集的和

完全背包

模板1

// 最值型完全背包
// 朴素解法
for (int i=1; i<=n; i++)
    for (int j=0; j<=m; j++)
    {
        dp[i][j] = dp[i-1][j];
        if (j>=v[i])
            dp[i][j] = max(dp[i][j], dp[i][j-v[i]]+w[i]);
    }
// 一维数组优化
for (int i=1; i<=n; i++)
    for (int j=v[i]; j<=m; j++)
        dp[j] = max(dp[j], dp[j-v[i]]+w[i]);

题解:AcWing 3 完全背包问题

模板2

// 布尔型完全背包
dp[j] |= dp[j-w[i]]

题解:洛谷 2737 麦香牛块

模板3

// 计数型完全背包
dp[j] += dp[j-w[i]]
dp[j] = min(dp[j], dp[j-w[i]]+1)

题解:洛谷 1679 神奇的四次方数

题解:质数和分解

posted @ 2026-02-20 22:59  团爸讲算法  阅读(4)  评论(0)    收藏  举报