动态规划不同的子序列
Posted 富春山居_ZYY
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了动态规划不同的子序列相关的知识,希望对你有一定的参考价值。
话不多说,上题!
题目:给定两个字符串S和T,返回S子序列等于T的不同子序列个数有多少个?
字符串的子序列是由原来的字符串删除一些字符(也可以不删除)在不改变相对位置的情况下的剩余字符(例如,"ACE"is a subsequence of"ABCDE"但是"AEC"不是)
例如:
S=“nowcccoder”, T = “nowccoder”
返回3
一、题意分析
字符串子序列概念:
根据题目所述,字符串的子序列就是在不改变字符的位置的情况下,对字符进行部分删除(也可以不删除)而得到的字符串就是该字符串的子序列
例如:字符串“abc”的子序列就有“a”,“b”,“c”,“ab”,“ac”,“bc”,“abc”。但是“ba”这样的字符串就不是原来的字符串的子序列,因为改变了字符的相对位置。
需求分析:
有俩字符串S和T,要求的就是S的子序列中有多少个子序列是和T字符串一模一样
例如:S=“nowcccoder”, T = “nowccoder”
想要满足题意,S的子序列可以是“now ccoder”(没用第一个c),“nowc coder”(没用第二个c),“nowcc oder”(没用第三个c),所以结果为3
二、思路分析
可以将子问题分成S的子串中与T相同的子序列的个数,那么在状态分析的时候,状态F(i)就应该是S的前i个字符构成的子串与T相同的子序列的个数,并且需要保证子串的长度比T字符串长,虽然看上去没什么问题,但是实际分析实例的时候就会出现问题
例如:S=“abaaa”,T=“aba”,显而易见,F(3) = 1,但当求F(4)时,我们知道S字符串中的第四个字符是“a”和T字符串最后一个字符相同,有被使用的价值,如果被使用的话,就意味着前面的字符串必须得是“ab”然后在拼接上第4个字符“a”,就意味着需要将S字符串的第三个字符“a”删除,使之和T字符串的前两个字符组成的子字符串相同。但是状态中并没有对S字符串的子串与T字符串前两个字符相同的子序列个数进行推导分析,不符合状态推导。
因此真正的状态应该改成S的前i个字符中与T的前j个字符相同的子序列的个数
。
-
当
第i个字符和第j个字符相同
时,说明该字符可以被使用。- 如果S中的第i个字符被使用了,那么需要在S字符串的前i-1个字符中找与T中前j-1个字符相同的子序列;
- 如果没有被使用,那么需要在S字符串的前i-1个字符中找与T中前j个字符相同的子序列。
-
若是
第i个字符和第j个字符不相同
时,那么该字符没有被使用的可能。- 只能从S字符串的前i-1个字符中找与T中前j个字符相同的子序列。
初始值设置就是S字符串前0个字符与T字符串前0个字符相同的子序列有1个
动态规划四个角度:
状态定义F(i,j)
:S的前i个字符中与T的前j个字符相同的子序列的个数
状态间的转移方程定义
:
S[i] == T[j]
,如果使用S[i] ,F(i,j)= F(i-1,j-1);如果不使用,F(i,j)= F(i-1,j)。因此F(i,j)= F(i-1,j-1)+ F(i-1,j)
s[i] != T[j]
,F(i,j)= F(i-1,j)
状态的初始化
:F(i,0)= 1
(表示S的子串与空串相同的个数,只有空串与空串相同)
返回结果
:F(S.length(),T.length())
三、代码结果
public int numDistinct (String S, String T)
int row = S.length();
int col = T.length();
int[][] num = new int[row + 1][col + 1];//存放状态
num[0][0] = 1;
for(int i = 1;i <= row;i ++)
num[i][0] = 1;//状态初始化
for(int j = 1;j <= col;j ++)
if(S.charAt(i-1) == T.charAt(j-1))
num[i][j] = num[i-1][j-1] + num[i-1][j];
//S的第i个字符和T的第j个字符相同
else
num[i][j] = num[i-1][j];
//S的第i个字符和T的第j个字符不相同
return num[row][col];//返回结果
四、代码升级
实际上,我们在求num[i][j](状态F(i,j))的时候只使用了num二维矩阵的第i-1行的数据,因此只需要使用一个一维数组(大小为T字符串的大小加一)进行存储数据即可,并且第二层循环一定要从后向前进行,如果从前向后,那么使用的数据即状态都是本行的而不是上一行的,会出现差错,关于这一点在01背包问题中也说过,这里就不多加解释。
public int numDistinct (String S, String T)
int row = S.length();
int col = T.length();
int[] num = new int[col + 1];//存放状态
num[0] = 1;
for(int i = 1;i <= row;i ++)
for(int j = col;j >= 1;j --)
if(S.charAt(i-1) == T.charAt(j-1))
num[j] = num[j-1] + num[j];//状态转移方程
return num[col];//返回结果
完!
以上是关于动态规划不同的子序列的主要内容,如果未能解决你的问题,请参考以下文章