本文始發於我的公衆號: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 排版