【Scramble String】cpp
题目:
Given a string s1, we may represent it as a binary tree by partitioning it to two non-empty substrings recursively.
Below is one possible representation of s1 = "great":
great
/ \
gr eat
/ \ / \
g r e at
/ \
a t
To scramble the string, we may choose any non-leaf node and swap its two children.
For example, if we choose the node "gr" and swap its two children, it produces a scrambled string "rgeat".
rgeat
/ \
rg eat
/ \ / \
r g e at
/ \
a t
We say that "rgeat" is a scrambled string of "great".
Similarly, if we continue to swap the children of nodes "eat" and "at", it produces a scrambled string "rgtae".
rgtae
/ \
rg tae
/ \ / \
r g ta e
/ \
t a
We say that "rgtae" is a scrambled string of "great".
Given two strings s1 and s2 of the same length, determine if s2 is a scrambled string of s1.
代码:
class Solution {
public:
bool isScramble(string s1, string s2) {
const int n1 = s1.size();
const int n2 = s2.size();
if (n1!=n2) { return false; }
const int n = n1;
int alpha[] = {};
for ( int i=; i<n; ++i ){ alpha[s1[i]-'a']++; alpha[s2[i]-'a']--; }
for ( int i=; i<; ++i ){ if ( alpha[i]!= ) return false; }
// terminal condition
if ( n== ) return s1[]==s2[];
// recursive process
for ( int i=; i<n; ++i ){
//cout << s1 << "," << s2 << ":" << i << endl;
if (
(
Solution::isScramble(s1.substr(,i), s2.substr(,i)) &&
Solution::isScramble(s1.substr(i,n-i), s2.substr(i,n-i))
)
||
(
Solution::isScramble(s1.substr(,i), s2.substr(n-i,i)) &&
Solution::isScramble(s1.substr(i,n-i), s2.substr(,n-i))
)
)
{ return true; }
}
return false;
}
};
tips:
这道题的题意自己并没有理解好,引用一个网上其他人的理解如下:
(http://www.blogjava.net/sandy/archive/2013/05/22/399605.html)
由于一个字符串有很多种二叉表示法,貌似很难判断两个字符串是否可以做这样的变换。
“对付复杂问题的方法是从简单的特例来思考,从而找出规律。
先考察简单情况:
字符串长度为1:很明显,两个字符串必须完全相同才可以。
字符串长度为2:当s1="ab", s2只有"ab"或者"ba"才可以。
对于任意长度的字符串,我们可以把字符串s1分为a1,b1两个部分,s2分为a2,b2两个部分,满足((a1~a2) && (b1~b2))或者 ((a1~b2) && (a1~b2))”
理解了题意,代码也就写出来了。
具体还有几个细节需要注意:
1. 为了剪枝并加快速度,做了如下几件事情:
a) 判断s1与s2的长度是否相等
b) 判断s1与s2的每个字符数量是否相等(这里由于是字母所以用一个定长数组alpha[26]表示:某个字母在s1中出现一次+1,在s2中出现一次-1;最终alpha的每个元素都是0则证明s1与s2的每个字符数量相等。扩展一下,如果字符不止26个字母,包含其他字符呢?可以用hashmap表示)
2. 设定终止条件:
如果s1和s2长度已经为1,无法再分割了,就直接比较即可。
3. 在递归传入参数的时候,用到了substr(begin, num):
a) begin代表切取的第一个字符下标,num代表截取几个字符
b) 注意每次传入isScramble的字符长度相等
===========================================
上述的做法类似记忆化搜索,网上还有一种动态规划的解法,也学习了吧。
(http://blog.csdn.net/linhuanmars/article/details/24506703)
class Solution {
public:
bool isScramble(string s1, string s2) {
const int n1 = s1.size();
const int n2 = s2.size();
if ( n1 != n2 ) return false;
const int n = n1;
vector<vector<vector<bool> > > dp(n,vector<vector<bool> >(n,vector<bool>(n+,false)));
for ( int k=; k<=n; ++k )
{
for ( int i=; i<=n-k; ++i )
{
for ( int j=; j<=n-k; ++j )
{
if ( k== )
{
dp[i][j][k] = s1[i]==s2[j];
continue;
}
for ( int l=; l<k; ++l )
{
dp[i][j][k] =
(dp[i][j][l] && dp[i+l][j+l][k-l])
||
(dp[i][j+k-l][l] && dp[i+l][j][k-l]);
if ( dp[i][j][k] ) break;
}
}
}
}
/*
for ( int k=0; k<=n; ++k )
{
cout << k << endl;
for ( int i=0; i<n; ++i)
{
for (int j=0; j<n; ++j )
{
cout << dp[i][j][k] << " ";
}
cout << endl;
}
}
*/
return dp[][][n];
}
};
tips:
AC之后发现这道题的dp思路其实可以由递归思路得来。
递归算法在不断的递归过程中,其实是一直再算s1的某一段与s2等长的某一段是否符合scramble的特点;注意,这里的某一段不一定指的是s1和s2从同一个位置开始。递归过程中,并没有记录这样的s1、s2字串比较的历史信息;而dp的解法是比较一次记录一次比较的历史信息,下次再判断的时候就可以利用上历史的比较信息了。
dp的过程(http://blog.csdn.net/linhuanmars/article/details/24506703)已经说的很好了。
这里有个细节需要注意一下,就是最外层的循环k代表从s1和s2截取字符串的长度。这里为了在下标表示方便,定义为n+1维;这样的好处就在于循环中的k直接表示的就是需要比较的子字符串的长度,不用考虑k-1这一类的内容。
这题的dp思路太精妙,只能学习膜拜。
完毕。
===================================================
第二次过这道题,dp的做法没时间去过了,用“深搜+剪枝”的做法更直观一些。
class Solution {
public:
bool isScramble(string s1, string s2) {
if ( s1.size()!=s2.size() ) return false;
int count[] = {};
for ( int i=; i<s1.size(); ++i ){
count[(int)s1[i]]++;
count[(int)s2[i]]--;
}
for ( int i=; i<; ++i ) { if ( count[i]!= ) return false; }
if ( s1.size()== ) return s1[]==s2[];
for ( int l=; l<s1.size(); ++l ){
bool possible = Solution::isScramble(s1.substr(,l), s2.substr(,l)) &&
Solution::isScramble(s1.substr(l, s1.size()-l), s2.substr(l, s2.size()-l));
if ( possible ) return true;
possible = Solution::isScramble(s1.substr(,l), s2.substr(s2.size()-l,l)) &&
Solution::isScramble(s1.substr(l,s1.size()-l), s2.substr(,s2.size()-l));
if ( possible ) return true;
}
return false;
}
};
【Scramble String】cpp的更多相关文章
- 【Interleaving String】cpp
题目: Given s1, s2, s3, find whether s3 is formed by the interleaving of s1 and s2. For example,Given: ...
- 【Valid Sudoku】cpp
题目: Determine if a Sudoku is valid, according to: Sudoku Puzzles - The Rules. The Sudoku board could ...
- 【WildCard Matching】cpp
题目: Implement wildcard pattern matching with support for '?' and '*'. '?' Matches any single charact ...
- 【Add binary】cpp
题目: Given two binary strings, return their sum (also a binary string). For example,a = "11" ...
- 【Implement strStr() 】cpp
题目: Implement strStr(). Returns the index of the first occurrence of needle in haystack, or -1 if ne ...
- 【Valid Palindrome】cpp
题目: Given a string, determine if it is a palindrome, considering only alphanumeric characters and ig ...
- 【Valid Parentheses】cpp
题目: Given a string containing just the characters '(', ')', '{', '}', '[' and ']', determine if the ...
- 【Simplify Path】cpp
题目: Given an absolute path for a file (Unix-style), simplify it. For example,path = "/home/&quo ...
- 【Valid Number】cpp
题目: Validate if a given string is numeric. Some examples:"0" => true" 0.1 " = ...
随机推荐
- 全面理解HTTP协议
引言:作为一名软件工程Web专业学生,对于HTTP的熟悉掌握是必不可少的,特此做记录,打造自己的HTTP栈. URL与URI 我们经常接触到的就是URL了,它就是我们访问web的一个字符串地址,那么U ...
- 9.26<立方网>技术笔试题
该公司题目感觉不难,算法设计有三道大题. 1.设有m和n两个整数,求它们的最大公约数和最小公倍数. 2.猴子分桃问题,每次分桃多一个,共有五个猴子,问最少有多少个桃子. 3.关于java的题目,有A, ...
- jquery mmgrid使用
参考 http://miemiedev.github.io/mmGrid/examples/index.html
- javascript的Array.prototype.map()和jQuery的jQuery.map()
两个方法都可以根据现有数组创建新数组,但在使用过程中发现有些不同之处 以下面这个数据为例: var numbers = [1, 3, 4, 6, 9]; 1. 对undefined和null的处理 a ...
- mysql服务器系统优化
1.选择合适的IO调度 对于mysql的系统,如果是SSD,那么应该使用NOOP调度算法,如果是磁盘,就应该使用Deadline调度算法.默认是CFQ echo dealine > /sys/b ...
- NOIP2018赛前停课集训记——最后的刷板子计划
前言 再过两天就\(NOIP2018\)了. 于是,我决定不做其他题目,开始一心一意刷板子了. 这篇博客记录的就是我的刷板子计划. [洛谷3383][模板]线性筛素数 这种普及-的题目我还写挂了两次( ...
- Object.prototype.toString的应用
使用Object.prototype上的原生toString()方法判断数据类型,使用方法如下: Object.prototype.toString.call(value)1.判断基本类型: Obje ...
- 2018.6.7. 云服务器Centos系统使用yum或者rpm安装包时出现问题,安装时报出错误:
当我向终端输入 sudo yum groupinstall chinese-support 语言安装包的时候显示下面的错误 error: rpmdb: BDB0113 Thread/process 3 ...
- 国产中标麒麟Linux部署dotnet core 环境并运行项目 (一) 安装dotnet core
背景 根据我之前写的文章 将 Net 项目升级 Core项目经验:(一)迁移Net项目为Net Core\Standard项目,我们将公司内部最核心的ORM框架迁移到net core 上面,并在win ...
- Windows10系统下查看mysql的端口号并修改
mysql的端口号默认是3306,初学者可能有时会忘记或者之前修改了默认的端口号,忘记了,或者很多时候我们一台电脑需要安装两个mysql或者想设置一个自己的喜欢的数字,那么接下来我们来看看如何查看或者 ...