自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

一篇學(xué)會復(fù)原IP地址!

網(wǎng)絡(luò) 通信技術(shù)
有效的 IP 地址 正好由四個整數(shù)(每個整數(shù)位于 0 到 255 之間組成,且不能含有前導(dǎo) 0),整數(shù)之間用 '.' 分隔。

[[426350]]

復(fù)原IP地址

給定一個只包含數(shù)字的字符串,復(fù)原它并返回所有可能的 IP 地址格式。

有效的 IP 地址 正好由四個整數(shù)(每個整數(shù)位于 0 到 255 之間組成,且不能含有前導(dǎo) 0),整數(shù)之間用 '.' 分隔。

例如:"0.1.2.201" 和 "192.168.1.1" 是 有效的 IP 地址,但是 "0.011.255.245"、"192.168.1.312" 和 "192.168@1.1" 是 無效的 IP 地址。

示例 1:

  • 輸入:s = "25525511135"
  • 輸出:["255.255.11.135","255.255.111.35"]

示例 2:

  • 輸入:s = "0000"
  • 輸出:["0.0.0.0"]

示例 3:

  • 輸入:s = "1111"
  • 輸出:["1.1.1.1"]

示例 4:

  • 輸入:s = "010010"
  • 輸出:["0.10.0.10","0.100.1.0"]

示例 5:

  • 輸入:s = "101023"
  • 輸出:["1.0.10.23","1.0.102.3","10.1.0.23","10.10.2.3","101.0.2.3"]

提示:

  • 0 <= s.length <= 3000
  • s 僅由數(shù)字組成

思路

做這道題目之前,最好先把131.分割回文串這個做了。

這道題目相信大家剛看的時候,應(yīng)該會一臉茫然。

其實(shí)只要意識到這是切割問題,切割問題就可以使用回溯搜索法把所有可能性搜出來,和剛做過的131.分割回文串就十分類似了。

切割問題可以抽象為樹型結(jié)構(gòu),如圖:

復(fù)原IP地址

回溯三部曲

  • 遞歸參數(shù)

在131.分割回文串中我們就提到切割問題類似組合問題。

startIndex一定是需要的,因?yàn)椴荒苤貜?fù)分割,記錄下一層遞歸分割的起始位置。

本題我們還需要一個變量pointNum,記錄添加逗點(diǎn)的數(shù)量。

所以代碼如下:

  1. vector<string> result;// 記錄結(jié)果 
  2.  // startIndex: 搜索的起始位置,pointNum:添加逗點(diǎn)的數(shù)量 
  3.  void backtracking(string& s, int startIndex, int pointNum) { 
  • 遞歸終止條件

終止條件和131.分割回文串情況就不同了,本題明確要求只會分成4段,所以不能用切割線切到最后作為終止條件,而是分割的段數(shù)作為終止條件。

pointNum表示逗點(diǎn)數(shù)量,pointNum為3說明字符串分成了4段了。

然后驗(yàn)證一下第四段是否合法,如果合法就加入到結(jié)果集里

代碼如下:

  1. if (pointNum == 3) { // 逗點(diǎn)數(shù)量為3時,分隔結(jié)束 
  2.     // 判斷第四段子字符串是否合法,如果合法就放進(jìn)result中 
  3.     if (isValid(s, startIndex, s.size() - 1)) { 
  4.         result.push_back(s); 
  5.     } 
  6.     return
  • 單層搜索的邏輯

在131.分割回文串中已經(jīng)講過在循環(huán)遍歷中如何截取子串。

在for (int i = startIndex; i < s.size(); i++)循環(huán)中 [startIndex, i]這個區(qū)間就是截取的子串,需要判斷這個子串是否合法。

如果合法就在字符串后面加上符號.表示已經(jīng)分割。

如果不合法就結(jié)束本層循環(huán),如圖中剪掉的分支:

復(fù)原IP地址

然后就是遞歸和回溯的過程:

遞歸調(diào)用時,下一層遞歸的startIndex要從i+2開始(因?yàn)樾枰谧址屑尤肓朔指舴?),同時記錄分割符的數(shù)量pointNum 要 +1。

回溯的時候,就將剛剛加入的分隔符. 刪掉就可以了,pointNum也要-1。

代碼如下:

  1. for (int i = startIndex; i < s.size(); i++) { 
  2.     if (isValid(s, startIndex, i)) { // 判斷 [startIndex,i] 這個區(qū)間的子串是否合法 
  3.         s.insert(s.begin() + i + 1 , '.');  // 在i的后面插入一個逗點(diǎn) 
  4.         pointNum++; 
  5.         backtracking(s, i + 2, pointNum);   // 插入逗點(diǎn)之后下一個子串的起始位置為i+2 
  6.         pointNum--;                         // 回溯 
  7.         s.erase(s.begin() + i + 1);         // 回溯刪掉逗點(diǎn) 
  8.     } else break; // 不合法,直接結(jié)束本層循環(huán) 

判斷子串是否合法

最后就是在寫一個判斷段位是否是有效段位了。

主要考慮到如下三點(diǎn):

  • 段位以0為開頭的數(shù)字不合法
  • 段位里有非正整數(shù)字符不合法
  • 段位如果大于255了不合法

代碼如下:

  1. // 判斷字符串s在左閉又閉區(qū)間[start, end]所組成的數(shù)字是否合法 
  2. bool isValid(const string& s, int start, int end) { 
  3.     if (start > end) { 
  4.         return false
  5.     } 
  6.     if (s[start] == '0' && start != end) { // 0開頭的數(shù)字不合法 
  7.             return false
  8.     } 
  9.     int num = 0; 
  10.     for (int i = start; i <= end; i++) { 
  11.         if (s[i] > '9' || s[i] < '0') { // 遇到非數(shù)字字符不合法 
  12.             return false
  13.         } 
  14.         num = num * 10 + (s[i] - '0'); 
  15.         if (num > 255) { // 如果大于255了不合法 
  16.             return false
  17.         } 
  18.     } 
  19.     return true

C++代碼

根據(jù)關(guān)于回溯算法,你該了解這些!給出的回溯算法模板:

  1. void backtracking(參數(shù)) { 
  2.     if (終止條件) { 
  3.         存放結(jié)果; 
  4.         return
  5.     } 
  6.  
  7.     for (選擇:本層集合中元素(樹中節(jié)點(diǎn)孩子的數(shù)量就是集合的大?。? { 
  8.         處理節(jié)點(diǎn); 
  9.         backtracking(路徑,選擇列表); // 遞歸 
  10.         回溯,撤銷處理結(jié)果 
  11.     } 

可以寫出如下回溯算法C++代碼:

  1. class Solution { 
  2. private: 
  3.     vector<string> result;// 記錄結(jié)果 
  4.     // startIndex: 搜索的起始位置,pointNum:添加逗點(diǎn)的數(shù)量 
  5.     void backtracking(string& s, int startIndex, int pointNum) { 
  6.         if (pointNum == 3) { // 逗點(diǎn)數(shù)量為3時,分隔結(jié)束 
  7.             // 判斷第四段子字符串是否合法,如果合法就放進(jìn)result中 
  8.             if (isValid(s, startIndex, s.size() - 1)) { 
  9.                 result.push_back(s); 
  10.             } 
  11.             return
  12.         } 
  13.         for (int i = startIndex; i < s.size(); i++) { 
  14.             if (isValid(s, startIndex, i)) { // 判斷 [startIndex,i] 這個區(qū)間的子串是否合法 
  15.                 s.insert(s.begin() + i + 1 , '.');  // 在i的后面插入一個逗點(diǎn) 
  16.                 pointNum++; 
  17.                 backtracking(s, i + 2, pointNum);   // 插入逗點(diǎn)之后下一個子串的起始位置為i+2 
  18.                 pointNum--;                         // 回溯 
  19.                 s.erase(s.begin() + i + 1);         // 回溯刪掉逗點(diǎn) 
  20.             } else break; // 不合法,直接結(jié)束本層循環(huán) 
  21.         } 
  22.     } 
  23.     // 判斷字符串s在左閉又閉區(qū)間[start, end]所組成的數(shù)字是否合法 
  24.     bool isValid(const string& s, int start, int end) { 
  25.         if (start > end) { 
  26.             return false
  27.         } 
  28.         if (s[start] == '0' && start != end) { // 0開頭的數(shù)字不合法 
  29.                 return false
  30.         } 
  31.         int num = 0; 
  32.         for (int i = start; i <= end; i++) { 
  33.             if (s[i] > '9' || s[i] < '0') { // 遇到非數(shù)字字符不合法 
  34.                 return false
  35.             } 
  36.             num = num * 10 + (s[i] - '0'); 
  37.             if (num > 255) { // 如果大于255了不合法 
  38.                 return false
  39.             } 
  40.         } 
  41.         return true
  42.     } 
  43. public
  44.     vector<string> restoreIpAddresses(string s) { 
  45.         result.clear(); 
  46.         if (s.size() > 12) return result; // 算是剪枝了 
  47.         backtracking(s, 0, 0); 
  48.         return result; 
  49.     } 
  50. }; 

總結(jié)

在131.分割回文串中我列舉的分割字符串的難點(diǎn),本題都覆蓋了。

而且本題還需要操作字符串添加逗號作為分隔符,并驗(yàn)證區(qū)間的合法性。

可以說是131.分割回文串的加強(qiáng)版。

在本文的樹形結(jié)構(gòu)圖中,我已經(jīng)把詳細(xì)的分析思路都畫了出來,相信大家看了之后一定會思路清晰不少!

本文轉(zhuǎn)載自微信公眾號「代碼隨想錄」,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請聯(lián)系代碼隨想錄公眾號。

 

責(zé)任編輯:武曉燕 來源: 代碼隨想錄
相關(guān)推薦

2022-01-02 08:43:46

Python

2022-02-07 11:01:23

ZooKeeper

2023-01-03 08:31:54

Spring讀取器配置

2021-05-11 08:54:59

建造者模式設(shè)計(jì)

2021-07-05 22:11:38

MySQL體系架構(gòu)

2021-07-06 08:59:18

抽象工廠模式

2022-08-26 09:29:01

Kubernetes策略Master

2023-11-28 08:29:31

Rust內(nèi)存布局

2021-07-02 09:45:29

MySQL InnoDB數(shù)據(jù)

2022-08-23 08:00:59

磁盤性能網(wǎng)絡(luò)

2021-10-27 09:59:35

存儲

2021-07-02 08:51:29

源碼參數(shù)Thread

2021-07-16 22:43:10

Go并發(fā)Golang

2022-04-12 08:30:52

回調(diào)函數(shù)代碼調(diào)試

2022-03-11 10:21:30

IO系統(tǒng)日志

2023-11-01 09:07:01

Spring裝配源碼

2023-03-13 21:38:08

TCP數(shù)據(jù)IP地址

2021-04-29 10:18:18

循環(huán)依賴數(shù)組

2021-10-14 10:22:19

逃逸JVM性能

2022-10-20 07:39:26

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號