最近几天在做区间型动态规划,刚开始一碰到字符串的问题就头疼,就会潜意识的跳过。真的静下心来做做 你会发现其实没你想的那么难。
一般经典的问题如:合并石子,回文字符串等。今天就说一下 回文字符串 和 括号匹配。
(1)回文字符串(nyoj 37)
-
描述
-
所谓回文字符串,就是一个字符串,从左到右读和从右到左读是完全一样的,比如"aba"。当然,我们给你的问题不会再简单到判断一个字符串是不是回文字符串。现在要求你,给你一个字符串,可在任意位置添加字符,最少再添加几个字符,可以使这个字符串成为回文字符串。
-
输入
-
第一行给出整数N(0<N<100)
接下来的N行,每行一个字符串,每个字符串长度不超过1000.
输出
- 每行输出所需添加的最少字符数 样例输入
-
1 Ab3bd
样例输出
-
2
方法一:
-
现将串倒置(如题中:db3bA),再求两个串(Ab3bd,db3bA)的最长公共子序列,可以看成是串本身存在最长的子回文序列,也就是不需要添加的,再用总长度减去最长公共子序列就可以得到最少需要添加的字符数。
- 这个思想和石子合并有点像。既然是区间型动态规划,我们就很容易想到先从小区间开始求,得到当前小区间i~j的最优解,然后再由小区间往外拓展求得更大的区间m~n(m<=i ,n>=j),最后就会得到整个串的最优解。 d[i][j] = d[i+1][j-1] (s[i] = s[j])
- d[i][j] = min(d[i+1][j] + 1, d[i][j-1] + 1) (s[i] != s[j])
方法二:
当s[i] = s[j]时,i位与j位相等不需要添加,直接等于d[i+1][j-1] 就行,当s[i] != s[j] 时,需要添加i或j位,选择花费最少的,即 min(d[i+1][j] + 1, d[i][j-1] + 1) 。
-
第一行给出整数N(0<N<100)
-
-
-
注:在我们求各个状态(区间)时应该先从小区间开始(求区间间隔为1时,再求区间间隔为2时......),不断扩大,最后求得整个区间。
(2)括号匹配(nyoj15)
-
-
-
描述
-
给你一个字符串,里面只包含"(",")","[","]"四种符号,请问你需要至少添加多少个括号才能使这些括号匹配起来。
如:
[]是匹配的
([])[]是匹配的
((]是不匹配的
([)]是不匹配的-
输入
-
第一行输入一个正整数N,表示测试数据组数(N<=10)
每组测试数据都只有一行,是一个字符串S,S中只包含以上所说的四种字符,S的长度不超过100
输出
- 对于每组测试数据都输出一个正整数,表示最少需要添加的括号的数量。每组测试输出占一行 样例输入
- 4
-
[] ([])[] ((] ([)]
样例输出
-
0 0 3 2
-
第一行输入一个正整数N,表示测试数据组数(N<=10)
-
给你一个字符串,里面只包含"(",")","[","]"四种符号,请问你需要至少添加多少个括号才能使这些括号匹配起来。
-
代码:
#include<iostream>
#include<cstdio>
#include<string.h>
#include<math.h>
using namespace std;
int len, d[110][110];
char s[110];
void dp()
{
for(int i = 1; i <= len-1; i++)
{
for(int j = 0; j < len-i; j++)
{
if((s[j]== '[' && s[j+i]==']') || (s[j]=='(' && s[j+i] == ')'))
{
if(i == 1)
d[j][i+j] = 0; //当j位与j+1位(相邻位)匹配时,不需要任何添加
else
d[j][j+i] = d[j+1][j+i-1]; //当j位于j+i位相匹配(但是不相邻),这时就需要由子区间(j+1,i+j-1)求得
}
else
d[j][j+i] = min(d[j+1][j+i]+1,d[j][i+j-1]+1); -
//注意:这块非常重要,这不仅需要遍历每种区间(d[j][j+i])的情况,而且需要求一下这种区间的最优解,即d[j][j+i]=min(d[j][j+i],d[j][k]+d[k+1][j+i])
for(int k = 0; k < j+i; k++)
d[j][j+i] = min(d[j][j+i],d[j][k]+d[k+1][j+i]);
}
}
}
int main()
{
int t;
cin >> t;
while(t--)
{
scanf("%s", &s);
len = strlen(s);
for(int i = 0; i <= len; i++)
{
for(int j = 0; j <= len; j++)
{
if(i == j)
d[i][j] = 1; //这也需要注意,不想回文单独的一位可以构成回文,这是单独的一个括号的一半需要有另一半匹配
else
d[i][j] = 10e8;
}
}
dp();
printf("%d\n", d[0][len-1]);
}
return 0;
}