Featured image of post 從LeetCode學演算法 - 81 Backtracking (5) / DFS (7)

從LeetCode學演算法 - 81 Backtracking (5) / DFS (7)

0093. Restore IP Addresses (Medium)

Question

Given a string containing only digits, restore it by returning all possible valid IP address combinations.

Example:

1
2
Input: "25525511135"
Output: ["255.255.11.135", "255.255.111.35"]

分析/解題

給定一個僅含數字0~9的字串,將其還原成所有合法的IP位址的可能組合。

對於IP而言,我們所需考慮的有以下幾個條件:
1. 共分4段(且必須恰好是4段)
2. 中間以小數點連接,每組的數字在0~255之間

如果定義再清楚一點的話,
可以補上前面寫0的部分除了0以外不能納入,會更好一點。
(比如113.002.22.3不會是合法的IP,但一個IP可以是0.0.0.0)

所以這題也是很典型的Backtracking+DFS 的題目:
每次從s上面按順序取一段長度,檢查它是否合法,
再遞迴取下一段。

那麼,我們需要考慮一些邊界的條件,
以便於我們考慮什麼時候該「回頭」:
最基本的條件,就是已經分到第4段 了,
我們應該要考慮這段剩下的部分是否合法。

  1. 當剩下的長度>3 => 根本就超過了,完全不用考慮XD
  2. 剩下的長度≤3且轉成數字≤255 ,即可將該段補齊並加到結果。
    例外:連續的0會有問題,所以要優先檢查是否剛好為'0’ 的狀況,
    除了剛好為"0"的狀況外,首字元為'0’就必須被排除掉

邊界條件考慮完後,我們來考慮一般的分段法。

在開始之前,可以先排除掉剩下的長度小於所需的分段數 的狀況,
用以避免取分段時超出邊界。
(例如剩下長度為2,但還需要取3段,那麼顯然不夠用)

假設現在我們接下來要取的位置在 i ,要取 j 個字元:
那麼 j可以是1~3,但 i+j 不能超過s的長度
我們會發現額外要考慮的就是上面的2的部分
取完一段以後,呼叫相同的函式進行遞迴,
不要忘記除了上一次傳進來的前導字串cur 外,
要加上的是這次取的分段 ,以及分隔用的小數點"."

依此,寫成程式碼如下:

Java

Java的部分,我們使用LinkedList來記錄結果res,
傳入的參數有該字串s,res,當前要取的索引值i,
當前的分段cnt(從0起算),以及到目前為止的IP的字串cur。
由於每次呼叫checkIP時帶進去的字串都是新生成 的,
所以回到上一層時就自然還原了cur的狀態,
不用像之前的棋盤搜尋字串問題中需要額外考慮要還原的問題。
每次開始前不要忘記檢查s.length()-i < 4 - cnt的邊界
若已經不符則可直接return。
(註:理論上也可以額外檢查s.length()-i > (4-cnt)*4的邊界,
但實測上並不會因此變快,推估可能理由和檢查255的問題一樣)

另外請務必留意在比較字串是否相等時請使用equals()的函式
不要使用"=="(會出錯)

Python

Python的部分也是一樣的概念,
只是substring的操作可以簡單用s[i:j] 的形式來處理,
且比較相等可以直接使用"=="。

面試實際可能會遇到的問題

「時間/空間複雜度?」
(O(len(s)) / O(len(s)),更廣義來說,其實長度必須在12 以內,
所以最大的佔用空間和時間是可以固定的
要說O(1)也不太算有錯就是了。)

「為什麼不是當3位數才檢查小於等於255?」
(這樣必須要先分開3位數及其他,變成要先經過另一組判斷式,
整體而言不會比較節省時間。)

相似及延伸

Special Thanks suggestions/corrections from viewers:
(歡迎提供意見協助更正歐~)

從LeetCode學演算法,我們下次見囉,掰~

感謝大家對這系列文章的支持!這邊跟大家自我工商一下:

筆者開設的系列同名線上課程:
「從Leetcode學演算法|基礎篇」已經上線啦! 在這堂課中,你將學會利用十種演算法/資料結構來優化解題過程,
並實際完整練習20題 精選考古題,
進而逐漸提升到不需提示也可以突破白板題,取得工作門票!
Medium優惠(最後一波早鳥優惠了,不確定調回原價是什麼時候): ** https://hiskio.com/courses/319?promo_code=VEQZV7E**

共發表了 171 篇文章 ‧ 總計 311.6k
使用 Hugo 建立
主題 StackJimmy 設計