题目如下: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. [leetcode] 提醒整理之进制

    12. Integer to Roman Given an integer, convert it to a roman numeral. Input is guaranteed to be with ...

  2. [资料分享]2016 黑马 Java 19期视频+Hadoop大数据实战视频

    下载链接: 链接:http://pan.baidu.com/s/1bToXK6 密码:7k43 解压密码: www.lthack.com 或者 2cifang.com 或者 2cifang.com_2 ...

  3. hihocoder挑战赛13A

    #1191 : 小W与网格 描述 给定一个n*m的网格,左上角(1, 1),右下角(n, m). 小w在(i, j),他会从"上左下右"四个方向中选定两个不同但正交的方向,然后他只 ...

  4. JavaScript使用封装

    基本封装方法 请看下面的例子: var Person = function(name,age){ this.name = name; this.age = age || "未填写" ...

  5. 【BZOJ1497】[NOI2006]最大获利 最小割

    裸的最小割,很经典的模型. 建图:要求总收益-总成本最大,那么将每条弧与源点相连,流量为成本,每个收益与汇点相连,流量为收益,然后每条弧与它所能到达的收益相连,流量为inf. 与源点相连的是未被选中的 ...

  6. 【BZOJ1911】[Apio2010]特别行动队 斜率优化DP

    想了好久啊....——黑字为第一次更新.——这里是第二次更新,维护上下凸包据题而论,第一种方法是化式子的方法,需要好的化式子的方法,第二种是偏向几何,十分好想,纯正的维护凸包的方法,推荐. 用了我感觉 ...

  7. jQuery中设置form表单中action的值的方法

    下面介绍在jQuery中设置form表单中action的值的方法. $("#myFormId").attr("action", "userinfo.s ...

  8. nodejs 单元测试

    之前项目开发因为改进度,基本都是粗放式开发.为了提高代码质量,单元测试是必不可少的. 针对restful api ,用supertest 测试框架.针对nodejs,引入mocha 和should 可 ...

  9. lua 时间戳和时间互转

    1.时间戳转换成时间 local t = 1412753621000 function getTimeStamp(t)     return os.date("%Y%m%d%H", ...

  10. Ubuntu环境变量(.profile)加载顺序

    Ubuntu下启动的时候的的加载环境变量的过程大致为: /etc/enviroment /etc/profile   -->/etc/bash.bashrc   --> /etc/prof ...