POJ 1159 Palindrome [动态规划+滚动数组]

POJ 1159 Palindrome [动态规划+滚动数组]

写在最前面:吹爆滚动数组!!!!!!!太好用了叭!!!快学它!!!

题目http://poj.org/problem?id=1159
题目大意:求最少增加几个字符可以使字符串s变成回文串
样例
输入:5
Ab3bd
输出:2
思路:动态规划

设置状态:f[i][j]的值表示从s[i]到s[j]至少增加几个字符可以使s[i…j]变成回文串
那么我们可以发现s[i]==s[j] 成立时,f[i][j]=f[i+1][j-1],只要使s[i+1…j-1]变成回文串即可
如果s[i]==s[j]不成立,可以使s[i+1…j]变成回文串后,再在s[j]后面增加一个s[i]的字符;同理,也可以使s[i…j-1]变成回文串后,再在s[i]前面增加一个s[j]的字符
f[i][j] = min(f[i+1][j],f[i][j-1])+1;
最终的结果为f[1][n];

状态转移

if (s[i] ==  s[j])
	f[i][j] = f[i+1][j-1];
else f[i][j] = min(f[i+1][j], f[i][j-1]) + 1;

注意点:
要注意一下下标i,j的循环顺序
由于计算f[i]是要计算f[i+1],所以i要从后往前枚举
由于计算f[j]是要计算f[j-1],所以j要从前往后枚举

for (int i(n); i >= n; --i)
for (int j(i); j <= n; ++j)

完整代码:

//POJ1159
#include <cstdio>
#include <algorithm>

using namespace std;

const int MAXN = 5123;
char s[MAXN];
int f[2][MAXN];

int main()
{
	int n;
	scanf ("%d", &n);
	
	for (int i(1); i <= n; ++i)
		scanf (" %c", &s[i]);
		
	for (int i = n; i >= 1; --i)
	for (int j = i; j <= n; ++j)
	{
		if (s[i] == s[j])
			f[i][j] = f[i+1][j-1];
		else f[i][j] = min(f[i+1][j], f[i][j-1])+1;
	}
	
	printf ("%d\n", f[1][n]);
		
	return 0;
}

提交代码!
AC!
等等!
好像
AC
MLE!

那我们就来算一下空间复杂度叭
512351234/1024 = 102520KB
(和f数组相比,s数组过小,可以忽略不计;
一个int,4个字节)
然而,Memory Limit: 65536KB
妥妥地超了
所以那我们该怎么办呢?
别急!
还记得我写在最前面的话么???!!!
吹爆滚动数组!!!

这个时候滚动数组上场了!!!
我们发现计算f[i][k]时只用到了f[i][k]或f[i+1]f[k](k为任意j值);
而i是顺序循环只做一遍,循环完就不要了
也就是说只需要保留上一组数据即可
那么将数组f[i][j]定义为f[2][MAXN]
根据i的奇偶性进行存储

if (s[i] == s[j])
	f[i%2][j] = f[(i+1)%2][j-1];
else f[i%2][j] = min(f[(i+1)%2][j], f[i%2][j-1])+1;

是不是空间一下子小了5678910倍???!!!
还是算一下叭
512324/1024 = 40KB
妥妥地没有超
是不是超棒!!!

好了,over

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值