题目如下:https://oj.leetcode.com/problems/interleaving-string/

Given s1, s2, s3, 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交织组成。乍一看并不是很难,但是仔细一想并没有那么简单。

第一个想法就是首先遍历s1和s3,将s1中出现的字母在s3中删除,然后再去比较剩下来的字符串是否与s2相同。但是很明显这个想法是错误的,因为同样的字母可能出现在s1和s2中,这样子s3中某一个字母匹配的可能是s1中的也可能是s2中的,所以这种解法是错误的。

这道题目正确的解法之一是利用动态规划,在列出答案之前先写一下如何去思考这个问题。

思考路径

从小规模的问题入手

首先,先将问题的规模缩小。缩到最小,假设s1和s2分别只有一个字符,那么我们会怎么去判断s3是否由s1和s2交织而成呢?

例-1

假设s1 = "a", s2 = "b", 's3 = "ab"'。那么我们的判断逻辑大概会是这样子:

  1. 如果s1的第一位和s3的第一位相同,则比较s2的第二位和s3的第二位,如果也相同则成立。
  2. 如果s2的第一位和s3的第一位相同,则比较s1的第二位和s3的第二位,如果也相同则成立。
  3. 没有符合条件的,则不成立。
	if (s1[0] == s3[0]){
if (s2[0] == s3[1]){
return true;
}
}
if (s2[0] == s3[0]){
if(s1[0] == s3[1]){
return true;
}
}
return false;

例-2 我们将规模稍微放大,假设s1 = "a", s2 = "bb", s3 = "abb"。我们来想想这个情况我们会怎么处理呢?

按照上面的思路,写出来的逻辑就是这样子的:

	if (s1[0] == s3[0]){
if (s2[0] == s3[1]){
if (s2[1] == s3[2]){
return true;
}
}
} if (s2[0] == s3[0]){
if (s1[0] == s3[1]){
if (s2[1] == s3[2]){
return true;
}
}
if (s2[1] == s3[1]){
if (s1[0] == s3[2]){
return true;
}
}
return false;
}

但是如果想一想,我们只是在s2和s3后面加了一个字符,我们完全没有必要重新开始判断。我们在第一个例子中已经知道了s1 = "a", s2 = "b", 's3 = "ab"'的结果,我们如果这个结果不成立,我们就没有必要再做判断了。如果成立的话我们也只需要将新加进来的字符判断一下就行了,如果相等则成立,不相等则不成立。这最大程度上的利用了已有的信息避免了重复的运算。

那我们尝试把例-1中的信息保存下来,可以得到下面这个图:

这个二维数组中的某个元素matrix[i][j]的含义可以理解为:s1.substring(0,i)s2.substring(0,j)这两个字符串组成s3.substring(0,i+j-1)字符串的可能组合。那么当s1或者s2任意一个字符串的长度增长的时候,我们只需要基于已有的可能性上再去比较新增加的字符即可。比如,上面的二维数组在例-2的情况下就演化为:

从图中很容易看出,当我们在s2中增加一个'b'的时候我们只需要计算martix[0][2]和martix[1][2],而这两个值分别是根据以后的数据演化出来的。matrix[0][1] => matrix[0][2], matrix[0][2] & matrix[1][1] => matrix[1][2]

总结

从上面的两个例子中我们可以得出,当某一个s1或s2中的某一个字符串增加一个字符的时候我们可以通过已有的数据推导出来新的结果集而不需要重新进行很多计算。所以我们可以将普通的字符串拆分成小规模的问题,通过这种累积的方式得到最终的结果。

而通过上面的那个矩阵,我们可以发现,如果我们想要知道字符串s3是否由s1和s2交织组成以及如何组成,我们需要算出一个$(len(s1) + 1) * (len(s2) + 1)$的矩阵,然后计算出matrix[len(s1)][len(s2)]的结果才能够得到答案。

当我们有两个字符串s1,s2的时候,我们将s1,s2当作和例-1中一样只有一个字符为开始,然后保持s1或s2的长度不变,而慢慢增加另一个字符串的长度来慢慢填充这个矩阵。算出整个矩阵后就得到了我们需要的答案。

实践

就拿s1 = "aabcc", s2 = "dbbca", s3 = "aadbbcbcac"为例子,我们尝试填充一个矩阵,它会是这样子的:

题目只要求判断结果,但是不需要列出可能的组合。所以我们其实没有必要存放组合,而是直接存一个布尔值判断是否有方案即可。

代码如下:

   public boolean isInterleave(String s1, String s2, String s3) {
if (s1 == null || s2 == null || s3 == null)
return false;
if (s1.length() + s2.length() != s3.length())
return false; boolean[][] matrix = new boolean[s1.length() + 1][s2.length() + 1];
matrix[0][0] = true;
for (int i = 1; i <= s2.length(); i++) {
if (s2.charAt(i - 1) == s3.charAt(i - 1))
matrix[0][i] = true;
else
break;
} for (int i = 1; i <= s1.length(); i++) {
if (s1.charAt(i - 1) == s3.charAt(i - 1))
matrix[i][0] = true;
else
break;
} for (int i = 1; i <= s1.length(); i++) {
for (int j = 1; j <= s2.length(); j++) {
if (s1.charAt(i - 1) == s3.charAt(i + j - 1))
matrix[i][j] = matrix[i - 1][j] || matrix[i][j];
if (s2.charAt(j - 1) == s3.charAt(i + j - 1))
matrix[i][j] = matrix[i][j - 1] || matrix[i][j];
}
}
return matrix[s1.length()][s2.length()];
}

Reference:

[LeetCode] Interleaving String - 交织的字符串的更多相关文章

  1. [LeetCode] Interleaving String 交织相错的字符串

    Given s1, s2, s3, find whether s3 is formed by the interleaving of s1 and s2. For example, Given: s1 ...

  2. Leetcode:Interleaving String 解题报告

    Interleaving StringGiven s1, s2, s3, find whether s3 is formed by the interleaving of s1 and s2. For ...

  3. [LeetCode] 97. Interleaving String 交织相错的字符串

    Given s1, s2, s3, find whether s3 is formed by the interleaving of s1and s2. Example 1: Input: s1 = ...

  4. [LeetCode] Interleaving String 解题思路

    Given s1, s2, s3, find whether s3 is formed by the interleaving of s1 and s2. For example,Given:s1 = ...

  5. [LeetCode] Interleaving String [30]

    题目 Given s1, s2, s3, find whether s3 is formed by the interleaving of s1 and s2. For example, Given: ...

  6. [LeetCode] Reverse String II 翻转字符串之二

    Given a string and an integer k, you need to reverse the first k characters for every 2k characters ...

  7. Interleaving String,交叉字符串,动态规划

    问题描述: Given s1, s2, s3, find whether s3 is formed by the interleaving of s1 and s2. For example,Give ...

  8. [Leetcode] Interleaving String

    Given s1, s2, s3, find whether s3 is formed by the interleaving of s1 and s2. For example,Given:s1 = ...

  9. [leetcode]Interleaving String @ Python

    原题地址:https://oj.leetcode.com/problems/interleaving-string/ 题意: Given s1, s2, s3, find whether s3 is ...

随机推荐

  1. 在WebStorm环境中给nodejs项目中添加packages

    照前文 http://www.cnblogs.com/wtang/articles/4133820.html  给电脑设置了WebStorm的IDE的nodejs开发环境.新建了个express的网站 ...

  2. WebGL与three.js

    前面学习了一些webgl的基础知识,现在就用一下three.js写一个小例子,记录一下学习的过程. 效果图: 1.去github下载three.js,然后将它加载到网页中 <script src ...

  3. 【iOS Instrument性能优化集】

    iOS Instrument性能优化集 1.UIImage缓存取舍 在项目代码中看到大量使用如下代码: UIImage使用 在Main Thread中发现不同动画场景中Image IO 开销和耗时所占 ...

  4. .NET程序运行过程产生的问题

    1.数据兼容性 功能模块的开发,会影响历史数据以及新数据的更新和体现.比如开发功能007,007支持了金额可变,数量不可变的原理.而历史数据均是数量可变,金额不可变的原理.此时,就会产生了问题. 2. ...

  5. 使用Mysql 5.5数据库Hibernate自动建表创建表出错table doesn't exist

    在mysql 5.0版本以后不支持 type=InnoDB 关键字,需要使用 engine=InnoDB 配置文件方言改成如下即可 <property name="dialect&qu ...

  6. Daily Scrum Meeting ——SixthDay(Beta)12.14

    一.Daily Scrum Meeting照片 二.Burndown Chart 三.项目进展(check-in) 1.完成注册界面中的学院.年级.身份选择. 2.补充参与者报名活动成功后按钮变为不可 ...

  7. Visual Studio 禁用Resharpe插件

    和普通的插件不一样,对于Resharper7+版本需要使用启动参数:/Resharper.Suspend

  8. 关于XML中:XmlNode和XmlElement的涵义及不同之处

    今天学习XML,遇到XmlNode和XmlElement俩个类,故有了下文的所述: 今天在做ASP.NET操作XML文档的过程中,发现了两个类:XmlNode和XmlElement.这两个类的功能极其 ...

  9. VirtualPathProvider的使用

    解决的问题,加载数据库中的UI public class Global : System.Web.HttpApplication { protected void Application_Start( ...

  10. bash 源码分析

    下载解压 bash-3.2 编译bash export LFS=/my/soft/mylfs tar xvf $LFS/sources/bash-3.2.tar.gz -C $LFS/sources/ ...