本文始发于个人公众号:TechFlow,原创不易,求个关注

今天是LeetCode专题第54篇文章,我们一起来看LeetCode 87题,Scramble String(爬行字符串)。

这题的官方难度是Hard,通过率33%,点赞506,反对702。看起来这题难度还可以,但是反对比点赞多,其实这题质量还不错,反对比较多我猜可能是因为题意稍稍有些复杂,理解起来不太容易,编码也偏难。但是这题如果是放在正式比赛中出现的话,都不叫事。

下面我们来看下题意。

题意

这题的题目叫做爬取字符串,看起来有些费解,其实这个爬取是题目中定义出来的一种操作,我们稍候结合样例来看很容易理解。首先,我们先把一个字符串拆分成二叉树的形式。

   great
/ \
gr eat
/ \ / \
g r e at
/ \
a t

也就是我们随机的选择分段点,每次都将字符串分割成两个部分。有了这棵二叉树之后,我们就可以进行爬取操作了。所谓的爬取操作,也就是调换这棵二叉树当中某一个节点的左右孩子的顺序。比如假设我们选择了对gr这个节点进行爬取,那么得到的结果如下:

    rgeat
/ \
rg eat
/ \ / \
r g e at
/ \
a t

我们还可以多次执行爬取,比如我们多次爬取操作之后可以得到一个全新的字符串rgtae.

    rgtae
/ \
rg tae
/ \ / \
r g ta e
/ \
t a

rgeat和rgtae都是从原字符串great进行一系列爬取操作之后得到的,题目会给定两个字符串s1和s2,要求我们给出能否通过对s1爬取操作得到字符串s2?

题解

不知道大家看完题意是什么感觉,是否觉得有些棘手呢?

棘手归棘手,但题目的要求还是很明确的。还是老规矩,我们一点点来分析问题。首先,那个花里胡哨的爬取操作是一个可逆操作,也就是说如果字符串s1能够通过这些操作变成s2,那么同样s2也可以通过同样的操作变回s1。从更高的层面来说,它们其实是一样的,是同一个存在的两个状态。

进一步,如果大家学过图论相关的算法,对这块有所了解的话,那么这个问题还可以进一步变形。

假设我们最初的字符串是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 排版

LeetCode 87,远看是字符串其实是搜索,你能做出来吗?的更多相关文章

  1. [LeetCode] 87. Scramble String 搅乱字符串

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

  2. [LeetCode] 87. Scramble String 爬行字符串

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

  3. Leetcode:003 无重复字符串

    Leetcode:003 无重复字符串 关键点:给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度.示例 1:输入: "abcabcbb"输出: 3 解释: 因为无重复 ...

  4. LeetCode刷题指南(字符串)

    作者:CYC2018 文章链接:https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/Leetcode+%E9%A2%98%E8%A7% ...

  5. LeetCode(43):字符串相乘

    Medium! 题目描述: 给定两个以字符串形式表示的非负整数 num1 和 num2,返回 num1 和 num2 的乘积,它们的乘积也表示为字符串形式. 示例 1: 输入: num1 = &quo ...

  6. Java 中字符串的子串搜索

    基友前两天参加了阿里的实习生面试,问了个问题,就是关于字符串的子串搜索的问题.想想实现方式无非就是两层循环,但是 java 中是有现成实现的,于是我就去查查源码,看看 java 语言怎么实现这个的,发 ...

  7. LeetCode初级算法的Python实现--排序和搜索、设计问题、数学及其他

    LeetCode初级算法的Python实现--排序和搜索.设计问题.数学及其他 1.排序和搜索 class Solution(object): # 合并两个有序数组 def merge(self, n ...

  8. 如何实现 Https拦截进行 非常规“抓包” 珍惜Any 看雪学院 今天 前段时间在自己做开发的时候发现一个很好用的工具,OKHttp的拦截器(何为拦截器?就是在每次发送网络请求的时候都会走的一个回调)大概效果如下:

    如何实现 Https拦截进行 非常规“抓包” 珍惜Any 看雪学院 今天 前段时间在自己做开发的时候发现一个很好用的工具,OKHttp的拦截器(何为拦截器?就是在每次发送网络请求的时候都会走的一个回调 ...

  9. LeetCode(87):扰乱字符串

    Hard! 题目描述: 给定一个字符串 s1,我们可以把它递归地分割成两个非空子字符串,从而将其表示为二叉树. 下图是字符串 s1 = "great" 的一种可能的表示形式. gr ...

  10. [leetcode]87. Scramble String字符串树形颠倒匹配

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

随机推荐

  1. servlet的四个作用域

    作用域规定的是变量的有效期限,servlet有四个作用域对象,这里只说三个: 一. request作用域: 1.作用范围: 就是指从http请求发起,到服务器处理结束,返回响应的整个过程.在这个过程中 ...

  2. [译]SQL Server分析服务的权限配置

    简介: 本文介绍如何配置SSAS数据库和cube相关维度的安全设置. 相对数据引擎来说,在Management Studio中配置分析服务的安全设置基本没什么区别.但是也会有一些限制,比如SSAS的权 ...

  3. 网页内嵌入QQ通信组件,唤起QQ,针对不同平台的处理方式

    web浏览器中嵌入QQ通信组件,目前发现有两种方式,主要是区分 IOS平台(苹果系列)和其他平台(PC 安卓等……),下面是代码区别: <li><a href="http: ...

  4. Saltstack系列1:安装配置

    安装 安装EPEL作为安装Ansible的yum源(CentOS6.4) rpm -Uvh http://ftp.linux.ncsu.edu/pub/epel/6/i386/epel-release ...

  5. php学习笔记1--开发环境搭建:apache+php+mysql

    php开发环境搭建:apache + php + mysql1.下载apache,php及mysql安装包2.安装apache:下载的apache若是.msi可直接双击,按指示一步一步安装:(若操作系 ...

  6. arcgis engine 开发之QI

    ArcGIS Engine开发基础之QI AO开发中QI(接口查询)非常重要,从某种意义上说不会QI就不会做AO开发. 在讲ArcGIS Engine开发QI实例操作之前,以一个现实生活例子以方便大家 ...

  7. memcpy、memmove、memset及strcpy函数实现和理解

    memcpy.memmove.memset及strcpy函数实现和理解 关于memcpy memcpy是C和C++ 中的内存拷贝函数,在C中所需的头文件是#include<string.h> ...

  8. 【Python系列】Python自动发邮件脚本-html邮件内容

    缘起 这段时间给朋友搞了个群发邮件的脚本,为了防止进入垃圾邮件,做了很多工作,刚搞完,垃圾邮件进入率50%,觉得还不错,如果要将垃圾邮件的进入率再调低,估计就要花钱买主机了,想想也就算了,先发一个月, ...

  9. maven工程 添加本地jar依赖

    和第三方平台对接的时候要用到对方提供的一个jar包,jar包怎么直接添加到pom文件的依赖中呢? jar包一般都是公共的,要上传到私服仓库.我们都是直接登录私服,操作仓库. 登录私服可以在项目的pom ...

  10. git 入门教程之基本概念

    基本概念 了解工作区,暂存区和版本库的区别和联系有助于我们更好理解 git 的工作流程,了解命令的操作意图. git 和其他版本控制系统如 svn 的不同之处就是有暂存区的概念. 基本概念 工作区 | ...