题目:

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.

代码:

“merge sort + stack”

        struct LastMatch{
int i1;
int i2;
int i3;
LastMatch(int i1, int i2, int i3): i1(i1), i2(i2), i3(i3){}
};
static bool isInterleave(string s1, string s2, string s3)
{
const int n1 = s1.size();
const int n2 = s2.size();
const int n3 = s3.size();
if ( n1+n2 != n3 ) return false;
stack<LastMatch> sta;
int i1=,i2=,i3=;
while ( i1<n1 || i2<n2 || i3<n3 )
{
if ( s1[i1]==s2[i2] && s2[i2]==s3[i3] ){
sta.push(LastMatch(i1,i2,i3));
i1++; i3++;
}
else if ( s1[i1]==s3[i3] ){
i1++; i3++;
}
else if ( s2[i2]==s3[i3] ){
i2++; i3++;
}
else if ( !sta.empty() ){
LastMatch lm = sta.top(); sta.pop();
i1 = lm.i1; i2 = lm.i2; i3 = lm.i3;
i2++; i3++;
}
else{
return false;
}
}
return i1==n1 && i2==n2 && i3==n3;
}

"dp"

class Solution {
public:
bool isInterleave(string s1, string s2, string s3)
{
const int n1 = s1.size();
const int n2 = s2.size();
const int n3 = s3.size();
if ( n1+n2 != n3 ) return false;
vector<vector<bool> > dp(n1+, vector<bool>(n2+, false));
dp[][] = true;
// check s1 boundary
for ( int i = ; i <= n1; ++i ){
dp[i][] = s1[i-]==s3[i-] && dp[i-][];
}
// check s2 boundary
for ( int i = ; i <= n2; ++i ){
dp[][i] = s2[i-]==s3[i-] && dp[][i-];
}
// dp process
for ( int i = ; i<=n1; ++i )
{
for ( int j = ; j<=n2; ++j )
{
dp[i][j] = ( s1[i-]==s3[i+j-] && dp[i-][j] )
|| ( s2[j-]==s3[i+j-] && dp[i][j-] );
}
}
return dp[n1][n2];
}
};

tips:

这道题第一版采用“merge sort + stack”,有一个大集合过不去,报超时(但即使跟可以AC的dp方法对比,“merge sort+stack”过这个大集合也仅仅慢了不到10%,在数量级上应该没有差别,时间复杂度都是O(n²))

dp的解法是学习网上的解法,理解如下:

dp[i][j]表示s1[0~i-1]与s2[0~j-1]是否匹配s3[0~i+j-1]

因此为了方便,定义dp[n+1][m+1],多一个维度,目的是保证从s1中取的个数从0到n都可以表示(s2同理)。

可以写出来dp的通项公式:

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

表示s3第i+j个元素要么由s1匹配上,要么由s2匹配上。

最后返回dp[n1][n2]就是所需的结果。

整个dp的过程并不复杂,思考下如何得来的:

1. dp取两个维度是因为s1和s2两个变量

2. 之前自己思考dp的时候,考虑的是每个位置可以由s1或者s2其中的元素表示,但是这样考虑起来就太复杂了;网上的思路并么有考虑到这么复杂,而是仅仅考虑s3中总共就这么长字符串,某个长度的字符串可以从s1和s2各取几个。

============================================

上述的dp过程的空间复杂度是O(n²)的,再采用滚动数组方式,把空间复杂度降低到O(n),代码如下:

class Solution {
public:
bool isInterleave(string s1, string s2, string s3)
{
const int n1 = s1.size();
const int n2 = s2.size();
const int n3 = s3.size();
if ( n1+n2 != n3 ) return false;
vector<bool> dp(n2+, false);
// check s2 boundary
dp[] = true;
for ( int i = ; i<=n2; ++i )
{
dp[i] = s2[i-]==s3[i-] && dp[i-];
}
// dp process
for ( int i = ; i<=n1; ++i )
{
dp[] = s1[i-]==s3[i-] && dp[];
for ( int j = ; j<=n2; ++j )
{
dp[j] = ( s1[i-]==s3[i+j-] && dp[j] ) || ( s2[j-]==s3[i+j-] && dp[j-] );
}
}
return dp[n2];
}
};

tips:如果二维的dp过程只跟紧上一次的dp过程有关,就可以退化为滚动数组形式的一维dp过程。

=======================================

第二次过这道题,参照dp的思路写了一遍。有个细节就是dp递推公式的时候“s3[i+j-1]”不要写成s3[i-1]或者s3[j-1]。

class Solution {
public:
bool isInterleave(string s1, string s2, string s3) {
if ( (s1.size()+s2.size())!=s3.size() ) return false;
bool dp[s1.size()+][s2.size()+];
fill_n(&dp[][], (s1.size()+)*(s2.size()+), false);
dp[][] = true;
for ( int i=; i<=s1.size(); ++i )
{
dp[i][] = dp[i-][] && s1[i-]==s3[i-];
}
for ( int i=; i<=s2.size(); ++i )
{
dp[][i] = dp[][i-] && s2[i-]==s3[i-];
}
for ( int i=; i<=s1.size(); ++i )
{
for ( int j=; j<=s2.size(); ++j )
{
dp[i][j] = ( dp[i-][j] && s1[i-]==s3[i+j-] ) ||
( dp[i][j-] && s2[j-]==s3[i+j-] );
}
}
return dp[s1.size()][s2.size()];
}
};

【Interleaving String】cpp的更多相关文章

  1. 【Scramble String】cpp

    题目: Given a string s1, we may represent it as a binary tree by partitioning it to two non-empty subs ...

  2. 【Valid Sudoku】cpp

    题目: Determine if a Sudoku is valid, according to: Sudoku Puzzles - The Rules. The Sudoku board could ...

  3. 【WildCard Matching】cpp

    题目: Implement wildcard pattern matching with support for '?' and '*'. '?' Matches any single charact ...

  4. 【Add binary】cpp

    题目: Given two binary strings, return their sum (also a binary string). For example,a = "11" ...

  5. 【Implement strStr() 】cpp

    题目: Implement strStr(). Returns the index of the first occurrence of needle in haystack, or -1 if ne ...

  6. 【Valid Palindrome】cpp

    题目: Given a string, determine if it is a palindrome, considering only alphanumeric characters and ig ...

  7. 【Valid Parentheses】cpp

    题目: Given a string containing just the characters '(', ')', '{', '}', '[' and ']', determine if the ...

  8. 【Simplify Path】cpp

    题目: Given an absolute path for a file (Unix-style), simplify it. For example,path = "/home/&quo ...

  9. 【Valid Number】cpp

    题目: Validate if a given string is numeric. Some examples:"0" => true" 0.1 " = ...

随机推荐

  1. SVN Working copy '***' locked

    问题描述: 用svn在项目文件夹下commit或者update时会出现错误提示“working copy locked” 解决方法: 1.在项目文件夹下,单击鼠标右键,选择tortoisesvn-&g ...

  2. c++编写递归函数char *itostr (int n,char *string),该函数将整数n转换为十进制表示的字符串。

    #include<iostream> #include<stdio.h> using namespace std; ; char *itostr (int n,char *St ...

  3. DDL与DML语句

    1. DDL语句 SQL语句:结构化查询语句,使用SQL与数据库“沟通”,完成相应的数据库操作. l DDL:数据定义语言,用来维护数据库对象 1.1 创建表 Ø CREATE:创建表 演示:创建员工 ...

  4. win10搜索不到蓝牙设备

    多半是驱动不兼容的问题. 解决方法: 此电脑右键,设备管理器,然后将蓝牙下的驱动,右键.卸载设备. 安装驱动精灵,会自动检测到缺少蓝牙驱动,安装即可.

  5. win8.1和wp8.1共用代码,需要注意的一些问题

    最近写了一个应有,使用了mvvmlight,把viewmodel.model.common之类的代码都放到了shared共享,写下来才发现,有不少问题是自已下手之前没注意到的,有些地方实在没法中途改了 ...

  6. POJ 1065 Wooden Sticks(LIS,最少链划分)

    题意:求二维偏序的最少链划分. 用到Dilworth定理:最少链划分=最长反链.(对偶也成立,个人认为区别只是一个维度上的两个方向,写了个简单的证明 相关概念:偏序集,链,反链等等概念可以参考这里:h ...

  7. UVA Live Archive 4394 String painter(区间dp)

    区间dp,两个str一起考虑很难转移. 看了别人题解以后才知道是做两次dp. dp1.str1最坏情况下和str2完全不相同,相当于从空白串开始刷. 对于一个区间,有两种刷法,一起刷,或者分开来刷. ...

  8. 动态规划专题(三)——数位DP

    前言 数位\(DP\) 真的是最恶心的\(DP\). 简介 看到那种给你两个数,让你求这两个数之间符合条件的数的个数,且这两个数非常大,这样的题目一般就是 数位\(DP\) 题. 数位\(DP\)一般 ...

  9. Linux常用的200个命令总结分类

    ●目录操作命令(6 个) ls tree pwd mkdir rmdir cd   ●文件操作命令(7 个) touch cp mv rm ln find rename   ●文件查看及处理命令(21 ...

  10. python剑指offer 顺时针打印指针

    题目描述 输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下4 X 4矩阵: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 则依次打印出数 ...