POJ1159——Palindrome——DP+滚动数组(节省空间)

Palindrome
Time Limit: 3000MS Memory Limit: 65536K
Total Submissions: 52154 Accepted: 17973

Description

A palindrome is a symmetrical string, that is, a string read identically from left to right as well as from right to left. You are to write a program which, given a string, determines the minimal number of characters to be inserted into the string in order to obtain a palindrome. 

As an example, by inserting 2 characters, the string "Ab3bd" can be transformed into a palindrome ("dAb3bAd" or "Adb3bdA"). However, inserting fewer than 2 characters does not produce a palindrome. 

Input

Your program is to read from standard input. The first line contains one integer: the length of the input string N, 3 <= N <= 5000. The second line contains one string with length N. The string is formed from uppercase letters from 'A' to 'Z', lowercase letters from 'a' to 'z' and digits from '0' to '9'. Uppercase and lowercase letters are to be considered distinct.

Output

Your program is to write to standard output. The first line contains one integer, which is the desired minimal number.

Sample Input

5
Ab3bd

Sample Output

2

Source



分析:动态规划+滚动空间。
此题很经典,题目花哨,问最少插入多少字符,是该字符串变成回文字符串。
DP。怎么构造? 我的修行不够啊,想不出来啊 F...
有一种是简单DP,dp[i][j]表示字符串从下标i到j 编程回文字符串最少需要插入的字符。状态转移方程如下:
for(int i=n-1;i>=0;i--)
{
for(int j=i+1;j<n;j++)
{
if(str[i] == str[j]) 
dp[i][j] = dp[i+1][j-1];
else 
dp[i][j] = min(dp[i][j-1], dp[i+1][j]) + 1;
}
}
能够得到正解,但是题目的核心不在此,且此解法内存超出 T_T
另辟蹊径>>>
其实和之前的那道DP是类似的,只需将输入的字符串逆序,然后求2个字符串的最长公共子序列的长度y,n-y即为answer。
DP和之前的做法一模一样。但是注意:由于数据范围达到了5000,内存超出。虽然投机取巧的开静态数组用short取代int能够过,但显然考验的不是这个。

隆重推出>>> 滚动数组。注意前提:状态转移方程dp[i][j]只依赖于dp[i-1][j]和dp[i][j-1];运用滚动数组dp[i%2][j] = dp[i%2][j-1] + dp[(i-1)%2][j]);

这样就节省了空间,但是时间上没有节省。
//用dp[5001][5001]内存超出
//必须节省空间,运用滚动数组
#include<iostream>
#include<string>
using namespace std;
/*
int dp[5001][5001] = {0};

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

	return 0;
}
*/

char str1[5001], str2[5001]; // str2为逆序
int dp[2][5001];

int main()
{
	int n;
	scanf("%d",&n);
	scanf("%s",str1);
	//逆序保存在str2
	for(int i=0;i<n;i++)
		str2[i] = str1[n-1-i];
	memset(dp, 0, sizeof(dp));
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++)
		{
			//dp[i][j] = max(dp[i][j-1], dp[i-1][j]);
			if(str1[i-1] == str2[j-1])
				dp[i%2][j] = dp[(i-1)%2][j-1] + 1;
			else
				dp[i%2][j] = max(dp[i%2][j-1], dp[(i-1)%2][j]);
		}
	}
	printf("%d\n",n-dp[n%2][n]); // n-dp[n%2][n]

	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值