您的位置:首页 > 其它

LeetCode 97. Interleaving String 题解

2017-11-27 10:59 281 查看

LeetCode 97. 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
.

题目大意

这道题是询问, 对于两个字符串
s1, s2
能否在不改变原字符串中字符出现顺序的情况下, 通过
s1,s2
字符的交替重组, 得到字符串
s3
.

思路分析

不难发现, 这道题和DP经典问题LCS之类很有相似之处。几乎可以马上做出采用DP的决定。并且复杂度为O(n2).关键在于转移方程。

转移方程即状态转移。下面以ans[i,j] 标识状态。 根据之前一些题目的经验, 可以马上推断出上一个状态为ans[i−1,j]和ans[i,j−1]。 其中ans[i,j]表示当
s1
的前
i
个字符与
s2
的前
j
个字符能够构成的
s3
的最长前缀长度。

明显的, 最后的判断即看ans[s1.size()][s2.size()]是否等于s3.size()

有一个很不顺的地方,在于初状态的构建。这题比较特别, 和LCS有较大的不同。

首先如果按照之前的初始化方法。 一般是构建状态数组的第一行与第一列。这里需要注意的是, 第一行与第一列,分别代表的意义是:当s1为空的时候, 以及s2 为空的时候的状态。

而普通的情况通常是, 第一行第一列是代表分别两个序列的第一个元素时的状态

之所以这样变,是考虑到如果不增加一个“空状态” 状态转移会变的突兀。 因为这时候可能会突然增加2个字符。原先的状态转移方程就不成立了。

下面是具体的代码。 是比较久之前写的了。 现在来看貌似仍有改进的余地:

class Solution {
public:
bool isInterleave(string s1, string s2, string s3) {
if (s3.size() != s1.size() + s2.size()) return false;
vector<vector<int> > ans(s1.size() + 1);

for (int i = 0; i < ans.size(); ++i) {
ans[i].resize(s2.size() +1);
}
for (int i = 1; i <= s1.size(); ++i) {
if (s3[i - 1] == s1[i - 1]) ans[i][0] = i;
else break;
}

for (int j = 1; j <= s2.size(); ++j) {
if (s3[j - 1] == s2[j - 1]) ans[0][j] = j;
else break;
}
for (int i = 1; i <= s1.size(); ++i) {
for (int j = 1; j <= s2.size(); ++j) {
if (s2[j - 1] == s3[ans[i][j - 1]]) {
ans[i][j] = max(ans[i][j], ans[i][j - 1] + 1);
}
if (s1[i - 1] == s3[ans[i - 1][j]]) {
ans[i][j] = max(ans[i][j], ans[i - 1][j] + 1);
}
}
}
return (ans[s1.size()][s2.size()] == s3.size());
}
};


其他细节

上面代码的时间复杂度已经达到O(n2)但是空间复杂度还有优化的余地。 判断空间复杂度是否可以优化只需要看当前状态是从哪些上一状态转移过来的。如果都只相邻的状态。 那么早先计算的大部分状态将不会被再次用到。 那么就进行了状态的压缩。

这道题的初始状态比较特殊。 自己要引起一些注意。

The End.

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  string leetcode