本文始发于我的公众号:TechFlow,原创不易,求个关注web
今天是LeetCode专题第54篇文章,咱们一块儿来看LeetCode 87题,Scramble String(爬行字符串)。算法
这题的官方难度是Hard,经过率33%,点赞506,反对702。看起来这题难度还能够,可是反对比点赞多,其实这题质量还不错,反对比较多我猜多是由于题意稍稍有些复杂,理解起来不太容易,编码也偏难。可是这题若是是放在正式比赛中出现的话,都不叫事。编辑器
下面咱们来看下题意。编码
这题的题目叫作爬取字符串,看起来有些费解,其实这个爬取是题目中定义出来的一种操做,咱们稍候结合样例来看很容易理解。首先,咱们先把一个字符串拆分红二叉树的形式。url
great / \ gr eat / \ / \ g r e at / \ a t
也就是咱们随机的选择分段点,每次都将字符串分割成两个部分。有了这棵二叉树以后,咱们就能够进行爬取操做了。所谓的爬取操做,也就是调换这棵二叉树当中某一个节点的左右孩子的顺序。好比假设咱们选择了对gr这个节点进行爬取,那么获得的结果以下:spa
rgeat / \ rg eat / \ / \ r g e at / \ a t
咱们还能够屡次执行爬取,好比咱们屡次爬取操做以后能够获得一个全新的字符串rgtae.code
rgtae / \ rg tae / \ / \ r g ta e / \ t a
rgeat和rgtae都是从原字符串great进行一系列爬取操做以后获得的,题目会给定两个字符串s1和s2,要求咱们给出可否经过对s1爬取操做获得字符串s2?ci
不知道你们看完题意是什么感受,是否以为有些棘手呢?字符串
棘手归棘手,但题目的要求仍是很明确的。仍是老规矩,咱们一点点来分析问题。首先,那个花里胡哨的爬取操做是一个可逆操做,也就是说若是字符串s1可以经过这些操做变成s2,那么一样s2也能够经过一样的操做变回s1。从更高的层面来讲,它们实际上是同样的,是同一个存在的两个状态。get
进一步,若是你们学过图论相关的算法,对这块有所了解的话,那么这个问题还能够进一步变形。
假设咱们最初的字符串是s,它经过一步爬取操做能够变成s1,s2和s3。那么咱们能够把这些字符串都抽象成一张无向图当中的节点。能够当作是s和s1,s2和s3之间有一条边相连。因此字符串之间可否经过爬取转化的关系就变成了在图上是否联通的关系,这个问题也就变成了在一张无向图当中已知两点,请问这两点是否联通。这个问题就简单多了,咱们遍历整张图就行了。
缩小到了图上遍历以后,整个问题其实已经出来了,遍历图无非两种方法,一种是深度优先搜索,一种是宽度优先搜索。这两种都是老掉牙的算法了,实在没什么稀奇的。在这题当中深搜宽搜都差很少,看你的喜爱了。我我的是选择的深搜实现的。
对于字符串的爬取操做而言,一共有两种可能,一种是s1拆分以后的两个部分分别和s2一样位置的两个部分的字符串进行比较。还有一种多是s1的前半部分和s2的后半部分,s1的后半部分和s2的前半部分判断。这两种状况实际上是同一个节点在搜索树上的两个支路,至关于咱们提早剪枝了,剪掉了不可能存在解的搜索子树,这个也是剪枝的常规作法。
你们可能感受这个题意比较复杂,可是最后的代码也许要比你们想的要简单:
class Solution:
def isScramble(self, s1: str, s2: str) -> bool:
from collections import Counter
def determine(s1, s2):
# 若是s1和s2构成的字符不一样,那么直接排除
c1 = Counter(list(s1))
c2 = Counter(list(s2))
return c1 == c2
def dfs(s1, s2):
# 若是要判断的s1和s2相等,返回True
if s1 == s2:
return True
if not determine(s1, s2):
return False
n = len(s1)
# 枚举拆分的位置将字符串拆分红两个部分
for i in range(1, n):
if dfs(s1[:i], s2[:i]) and dfs(s1[i:], s2[i:]) or dfs(s1[:i], s2[n-i:]) and dfs(s1[i:], s2[:n-i]):
return True
return False
if len(s1) != len(s2):
return False
if len(s1) == 0:
return True
return dfs(s1, s2)
今天的这道题就算是讲完了,虽然看起来涉及到各类字符串的操做,又是建树又是颠倒顺序什么的,但这题本质上实际上是一道搜索题。只要对搜索问题稍微熟悉一点,作出这道题并不困难,这也是本题经过率其实不算低的缘由。
在以前的文章当中也曾经提到过,不论是在LeetCode上也好,仍是在acm赛场上也罢,一道看似是字符串的问题最后经过建模转化成其余的算法模型是屡见不鲜的事情。你们作题的时候必定要思惟灵活,若是钻了牛角尖可能就解不出来了。
今天的文章到这里就结束了,若是喜欢本文的话,请来一波素质三连,给我一点支持吧(关注、转发、点赞)。
本文使用 mdnice 排版