LeetCode - interleaving-string

题目:

Given s1s2s3, find whether s3 is formed by the interleaving of s1 and s2.

For example,
Given:
s1 ="aabcc",
s2 ="dbbca",

When s3 ="aadbbcbcac", return true.
When s3 ="aadbbbaccc", return false.

 

题意:

判断s3是否由是s1,s2交叉得到。 这里的交叉是指顺序交叉,不能跳跃性交叉。

 

解题思路:

一般遇到字符串的子序列或者匹配问题,那么一般可以使用动态规划自底向上进行求解。这题与那个Word Break有点类似。

动态规划一般有两个难点,第一个难点就是边界的确认。

我们可以把例子的那两个s1,s2进行字符拆分。如下图所示(这图我是摘自http://www.cnblogs.com/grandyang/p/4298664.html

  Ø d b b c a  
Ø T F F F F F
a T F F F F F
a T T T T T F
b F T T F T F
c F F T T T T
c F F F T F T

这里我们可以使用一个dp[i][j]二维boolean数组来表示,i+j 表示s3是否由s1的前i个字符,s2的前j个字符构成。

我们可以看到,当s1,s2都为空串时,此时dp[0][0] = true,可以理解为s1中取0个字符 s2中取0个字符 匹配s3从0开始的0个字符 那么肯定匹配true

上边界可以表示为:dp[0][i] = dp[0][i-1] && (s2.charAt(i-1) == s3.charAt(i-1));  这里可以理解为从s1取0个字符,s2取i个字符去和s3 i+0个字符进行匹配,同时根据上一个位置的值来进行赋值(这里我觉得也体现了动态规划自底向上的一种思想,上一个的值总会影响下一个位置的值)

同理左边界可以表示为:dp[i][0] = dp[i-1][0] && (s1.charAt(i-1) == s3.charAt(i-1)); 这里可以理解为s2中取0个,s1中取i个 去和s3中0+i 个匹配,同时也根据上一个位置的值来进行赋值

这里边界就已经确定好了,下面就需要确认动态规划的公式了

这里的公式为:

dp[i][j] = (dp[i-1][j] && (s1.charAt(i-1) == s3.charAt(i-1+j))) || (dp[i][j-1] && (s2.charAt(j-1) == s3.charAt(j-1+i)));

这里面有两个动态转移方程

第一个是dp[i-1][j] && (s1.charAt(i-1) == s3.charAt(i-1+j)),这里可以理解为
dp[i-1][j]表示若s3的前i+j-1个字符能够由s1前i-1个字符和s2的前j个字符交织而成,那么只需要s1的第i个字符与s3的第i+j个字符相等(charAt索引从0开始),那么dp[i][j]=true;

第二个转移方程是:dp[i][j-1] && (s2.charAt(j-1) == s3.charAt(j-1+i)),这里也可以这么理解:
dp[i-1][j]表示若s3的前i+j-1个字符能够由s1前i个字符和s2的前j-1个字符交织而成,那么只需要s2的第j个字符与s3的第i+j个字符相等(charAt索引从0开始),那么dp[i][j]=true;

只要这两个转移方程有一个为true,那么就可以判断s3是由s1,s2交叉构成

 

下面给出代码:

 public static boolean isInterleave(String s1, String s2, String s3) {
		 
		int length1 = s1.length();
		int length2 = s2.length();
		int length3 = s3.length();
		
		if(length1 + length2 != length3) {
			return false;
		}
		
		boolean[][] dp = new boolean[length1+1][length2+1];
		//初始化边界
		dp[0][0] = true;
		//初始化第一行
		for(int i = 1;i <= length2;i++) {
			dp[0][i] = dp[0][i-1] && (s2.charAt(i-1) == s3.charAt(i-1));
		}
		//初始化第一列
		for(int i = 1;i <= length1;i++) {
			dp[i][0] = dp[i-1][0] && (s1.charAt(i-1) == s3.charAt(i-1));
		}
		
		//dp
		for(int i = 1;i <= length1;i++) {
			for(int j = 1; j <= length2; j++) {
				dp[i][j] = (dp[i-1][j] && (s1.charAt(i-1) == s3.charAt(i-1+j))) || (dp[i][j-1] && (s2.charAt(j-1) == s3.charAt(j-1+i)));
			}
		}
		return dp[length1][length2];
	        
	 }

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值