题目:

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. 小记:vue 及 react 的工程项目入口小结及 webpack 配置多页面应用参考

    一.前言 闲暇时间,看了下前端的基础知识,有幸参与了公司公众号项目前面的一个阶段,学习到了一些前端框架的相关知识 小结了一下 自己练习通过新建一个个文件组织起项目的过程中的一些理解 二.项目入口 vu ...

  2. NOIP2018提高组Day1 解题报告

    前言 关于\(NOIP2018\),详见此博客:NOIP2018学军中学游记(11.09~11.11). 这次\(NOIP\ Day1\)的题目听说很简单(毕竟是三道原题),然而我\(T3\)依然悲剧 ...

  3. AngularJs学习笔记-组件生命周期

    组件生命周期 (1)组件生命周期钩子 constructor:组件创建时被创建 ngOnChanges: 父组件修改或初始化子组件的输入属性时被调用,如果子组件没有输入属性,则永远不会被调用,它的首次 ...

  4. BeyondCompare:如何之比较文件内容的不同?

    问题描述: 在使用beyond compare比较文件的时候,常会有很多不同,但是点击打开后,发现内容没有不同.这个是因为工具把文件的日期.大小等非内容因素也比较了进去. 解决方法: 点击“会话” - ...

  5. Websocket教程SpringBoot+Maven整合

    1.大话websocket及课程介绍 简介: websocket介绍.使用场景分享.学习课程需要什么基础 2.课程技术选型和浏览器兼容讲解 简介: 简单介绍什么是springboot.socketjs ...

  6. Springboot端口设置

    application.properties 加入 server.port=80

  7. Java代码随机生成图片验证码

    package com.rchm.util.images; import java.awt.Color; import java.awt.Font; import java.awt.Graphics2 ...

  8. vim正则表达式的替换变量

    在正规表达式中使用 \( 和 \) 符号括起正规表达式,即可在后面使用\1.\2 等变量来访问 \( 和 \) 中的内容. 例如有下列英汉对照文本: adapter 适配器address 地址alge ...

  9. 爬取代理IP,并判断是否可用。

    # -*- coding:utf-8 -*- from gevent import monkey monkey.patch_all() import urllib2 from gevent.pool ...

  10. 三十三、MySQL 导入数据

    MySQL 导入数据 本章节我们为大家介绍几种简单的 MySQL 导出的数据的命令. 1.mysql 命令导入 使用 mysql 命令导入语法格式为: mysql -u用户名 -p密码 < 要导 ...