本文始发于个人公众号: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. 【python】Leetcode每日一题-扰乱字符串

    [python]Leetcode每日一题-扰乱字符串 [题目描述] 使用下面描述的算法可以扰乱字符串 s 得到字符串 t : 如果字符串的长度为 1 ,算法停止 如果字符串的长度 > 1 ,执行 ...

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

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

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

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

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

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

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

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

随机推荐

  1. Numerical Sequence (Hard vision) 题解

    The only difference between the easy and the hard versions is the maximum value of \(k\). You are gi ...

  2. day48 work

    1 navicat自己玩一玩 2 练习题一定要搞懂 照着我的思路一遍遍的看敲 3 熟悉pymysql的使用 4 sql注入产生的原因和解决方法 了解 5 思考:如何结合mysql实现用户的注册和登录功 ...

  3. php批量 下载图片

    <?php set_time_limit(0); $file = fopen("index.csv",'r');$temp = [];$i=0;$firstsku='';wh ...

  4. Flask 基础组件(六):Session

    除请求对象之外,还有一个 session 对象.它允许你在不同请求间存储特定用户的信息.它是在 Cookies 的基础上实现的,并且对 Cookies 进行密钥签名要使用会话,你需要设置一个密钥. 设 ...

  5. Flask 基础组件(五):请求和响应

    from flask import Flask from flask import request from flask import render_template from flask impor ...

  6. Linux下diff工具

    目录 CentOS 7为例 Meld DiffMerge KDiff3 Kompare CentOS 7为例 Meld Installation 官网 $ sudo yum install meld; ...

  7. Cyber Security - Palo Alto Basic Introduction

    Preparation of the Lab Environment: Download and Install Pan-OS from the following website https://d ...

  8. Python Ethical Hacking - KEYLOGGER(2)

    Report function: Run in the background. Don't interrupt program execution. Every X seconds, send the ...

  9. Shell基本语法---shell数组

    shell数组 arr=( ) #定义数组 echo ${#arr[*]} #打印数组长度 echo ${arr[]} #打印数组的第一个成员 echo ${arr[]} #打印数组的二个成员 ech ...

  10. C++语法小记---函数重载

    函数重载 函数重载的本质是对已有功能的扩展 构成重载的三大条件 函数名相同 参数列表不通(与返回值无关) 重载函数的作用域相同 成员函数之间可以重载,成员函数和静态成员函数之间可以构成重载,全局函数之 ...