【leetcode刷题笔记】Scramble String
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.
题解:
第一个想法比较naive,想把s1和s2都按照字典序排列,然后看是否相同。提交后就发现下面的例子就能够证明这个算法的错误:
s1 = "abcd"
s2 = "bdac"
第二个想法是递归,如下图所示:

对于任意长度相等的s1和s2,都可以分解成上图两种情况,通过把s1和s2分成两部分,那么有两种情况s1和s2是scramble的,一种是两部分对应scramble;一种是两部分交换后scramble。这样就有了我们的递归解法。
但是仅仅是这种递归一定会超时,必须进行优化,有一下几点可以优化的地方:
- s1和s2长度必须相等;
- 长度相等且都为0,返回true;
- s1和s2完全相同返回true;
- s1和s2所包含的字母种类个数必须相同,即s1和s2按照字典序排序后必须相同;
通过以上的优化,递归方法就不会超时了。
代码如下:
public class Solution {
public boolean isScramble(String s1, String s2) {
int m = s1.length();
int n = s2.length();
if(m != n)
return false;
if(m == 0 || s1.equals(s2))
return true;
char[] chars1 = s1.toCharArray();
char[] chars2 = s2.toCharArray();
Arrays.sort(chars1);
Arrays.sort(chars2);
for(int i = 0;i < m;i++)
if(chars1[i] != chars2[i])
return false;
for(int i = 1;i < m;i++){
String s1left = s1.substring(0,i);
String s1right = s1.substring(i);
String s2left = s2.substring(0, i);
String s2right = s2.substring(i);
if(isScramble(s1left, s2left) && isScramble(s1right, s2right))
return true;
s2left = s2.substring(0,n-i);
s2right = s2.substring(n-i);
if(isScramble(s1left, s2right) && isScramble(s1right, s2left))
return true;
}
return false;
}
}
上述方法耗时428ms。
第三个想法,动态规划。
递归之所以会超时,是因为做了许多重复的工作。用动态规划bottom-up的方法把这些重复的工作记录在表dp[][][]中,就可以省去重复计算的时间。
我们用dp[sublen][i][j]表示s1[i,i+sublen]和s2[j,j+sublen]是否是scramble的。那么有如下递推式:
dp[sublen][i][j] = (dp[k][i][j]&&dp[sublen-k][i+k][j+k]) || (dp[k][i][j+sublen-k] && dp[sublen-k][i+k][j]);
它对应了下图两种情况:

另外 dp[1][i][j] = s1.charAt(i) == s2.charAt(j);
理解还算容易,写代码还是有难度的,一共四重循环:
第一重循环改变sublen的大小,从长度为2的子串一直增加至长度为n的串;
第二重循环改变i,即s1中游标的位置,从0~n-sublen;
第三重循环改变i,即s2中游标的位置,从0~n-sublen;
第四重循环枚举从i~i+sublen之间的每一中分割字符串的位置,考察这样分割是否能使得s1和s2对应的部分scramble得到,k从1~sublen-1;
代码如下:
public class Solution {
public boolean isScramble(String s1, String s2) {
if(s1.length() != s2.length())
return false;
if(s1.length() == 0 && s2.length() == 0)
return true;
int n = s1.length();
boolean[][][] dp = new boolean[n+1][n+1][n+1];
for(int i = 0;i < n;i++){
for(int j = 0;j < n;j++)
dp[1][i][j] = s1.charAt(i) == s2.charAt(j);
}
for(int sublen = 2;sublen <= n;sublen++){
for(int i = 0;i <= n-sublen;i++){
for(int j = 0;j <= n-sublen;j++){
dp[sublen][i][j]= false;
for(int k = 1;k<sublen && dp[sublen][i][j]== false ;k++)
dp[sublen][i][j] = (dp[k][i][j]&&dp[sublen-k][i+k][j+k]) || (dp[k][i][j+sublen-k] && dp[sublen-k][i+k][j]);
}
}
}
return dp[n][0][0];
}
}
【leetcode刷题笔记】Scramble String的更多相关文章
- 【leetcode刷题笔记】String to Integer (atoi)
Implement atoi to convert a string to an integer. Hint: Carefully consider all possible input cases. ...
- LeetCode刷题笔记和想法(C++)
主要用于记录在LeetCode刷题的过程中学习到的一些思想和自己的想法,希望通过leetcode提升自己的编程素养 :p 高效leetcode刷题小诀窍(这只是目前对我自己而言的小方法,之后会根据自己 ...
- LeetCode刷题笔记 - 12. 整数转罗马数字
学好算法很重要,然后要学好算法,大量的练习是必不可少的,LeetCode是我经常去的一个刷题网站,上面的题目非常详细,各个标签的题目都有,可以整体练习,本公众号后续会带大家做一做上面的算法题. 官方链 ...
- 18.9.10 LeetCode刷题笔记
本人算法还是比较菜的,因此大部分在刷基础题,高手勿喷 选择Python进行刷题,因为坑少,所以不太想用CPP: 1.买股票的最佳时期2 给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格. ...
- Leetcode刷题笔记(双指针)
1.何为双指针 双指针主要用来遍历数组,两个指针指向不同的元素,从而协同完成任务.我们也可以类比这个概念,推广到多个数组的多个指针. 若两个指针指向同一数组,遍历方向相同且不会相交,可以称之为滑动窗口 ...
- 【leetcode刷题笔记】Interleaving String
Given s1, s2, s3, find whether s3 is formed by the interleaving of s1 and s2. For example,Given:s1 = ...
- 【leetcode刷题笔记】Reverse Words in a String
Given an input string, reverse the string word by word. For example,Given s = "the sky is blue& ...
- LeetCode刷题笔记(1-9)
LeetCode1-9 本文更多是作为一个习题笔记,没有太多讲解 1.两数之和 题目请点击链接 ↑ 最先想到暴力解法,直接双循环,但是这样复杂度为n平方 public int[] twoSum(int ...
- leetcode刷题笔记08 字符串转整数 (atoi)
题目描述 实现 atoi,将字符串转为整数. 在找到第一个非空字符之前,需要移除掉字符串中的空格字符.如果第一个非空字符是正号或负号,选取该符号,并将其与后面尽可能多的连续的数字组合起来,这部分字符即 ...
随机推荐
- Mysql的建表规范与注意事项
一. 表设计规范 库名.表名.字段名必须使用小写字母,“_”分割. 库名.表名.字段名必须不超过12个字符. 库名.表名.字段名见名知意,建议使用名词而不是动词. 建议使用InnoDB存储引擎. 存储 ...
- sublime 插件(持续更新)
sublime text 3创建新文件插件-AdvanceNewFile 这里要记录sublime text 3 在创建新文件时安装的插件–AdvanceNewFile ST本来自带的创建新文件的快捷 ...
- Hadoop 配置及hadoop HA 的配置
注:本文中提到的ochadoop 不要感到奇怪,是亚信公司内部自己合成的一个包.把全部的组件都放在一个包内了.免去了组件的下载过程和解决兼容问题.事实上也能够自己下载的.不要受到影响. 另,转载请注明 ...
- An error occurred while searching for implementations of method
1:在我安装完scala的插件后,在打开方法的实现类(open implementactions)的时候,抛出这个异常,后来发现这个异常是因为我的scala的插件跟我eclipse版本不兼容导致的. ...
- 小技巧之Selenium如何切换到弹出的Tab页中
今天群里讨论了一个问题,如何将selenium的操作焦点切换到浏览器中新弹出来的Tab页中,正好对应到了昨天的那篇文章“小技巧之在浏览器中打开新的页签”.今天就带大家来解决这个问题: 先封装一个Tab ...
- 【JMeter4.0学习(二)】之搭建openLDAP在windows8.1上的安装配置以及JMeter对LDAP服务器的性能测试脚本开发
目录: 概述 安装测试环境 安装过程 配置启动 配置搭建OpenLDAP 给数据库添加数据 测试查询刚刚插入的数据 客户端介绍 JMeter建立一个扩展LDAP服务器的性能测试脚本开发 附:LDAP学 ...
- 深入了解Erlang 垃圾回收机制以及其重要性(转)
声明:本片文章是由Hackernews上的[Erlang Garbage Collection Details and Why ItMatters][1]编译而来,本着学习和研究的态度,进行的编译,转 ...
- LeakCanary Android 和 Java 内存泄露检测
说起内存泄漏还是挺让人头疼的,而且不是每个手机都会发生的情况,往往又不易察觉,那么今天我们就来介绍下LeakCanary这个工具 githup:https://github.com/square/le ...
- windows下XAMPP安装php_memcache扩展
windows下XAMPP安装php_memcache扩展 首先下载phpmemcache,地址为: http://up.2cto.com/2012/0522/20120522094758371.ra ...
- ios输出想保留的整数位(占位符)
int startHour=5; int startMinute=4; //输出前面补0,不管你输入的数据前面有没有0 sp;NSLog(@"====>%@",[NSStri ...