注:本題使用了分治的思想。
解題方法:遞歸法、暴力求解法
Leetcode 93
Given a string containing only digits, restore it by returning all possible valid IP address combinations.
For example:
Given “25525511135”,
return [“255.255.11.135”, “255.255.111.35”]. (Order does not matter)
題意:
- 給出一個字符串,然後你的程序需要解析出該字符串可能符合的所有合法ip地址並將之存儲在容器中。
思路:
先考慮合法ip地址的格式: “{0-255}.{0-255}.{0-255}.{0-255}”
ip地址由四個part和三個dot組成,每個part的位數爲1~3,每個part的值在0~255之間,且如果位數不是1位時,不能以0開頭,即不能存在011,01等情況。
先採用分治的思想
因爲ip地址是由四部分組成,每部分的構造與合法性要求是一致的,故我可以將分割字符串這個問題分成四個相同的小問題,然後採取遞歸的方式去解決它
因爲有四個相同的小問題,很明顯,要得到一個合法的ip地址,需要執行四層遞歸 ,所以需要傳入參數n來標識進行到第幾層遞歸。
然後需要傳入未切割的字符串、存儲當前遞歸得到的合法ip地址(一個)的String變量、還有存儲所有合法ip地址的vector容器
因爲對於每一個部分,有三種情況切割,即1位、2位、3位,故在遞歸函數中定義一層for循環用於分類討論,然後將各種分割情況的剩餘字符串傳入下一層遞歸函數中
代碼如下:
/*2017/9/10 93. Restore_IP_Address 的遞歸寫法(分治思想) 思路: 1.ip地址是四個部分,即需要將字符串切割成四部分; 2.需要對每一部分進行分類討論,即每部分是1位、2位或者是3位,且要對每一部分的合法性進行驗證,故 可以將問題分解成四個相同的小部分,然後用遞歸實現; 3.在每一次的遞歸中,由於需要分類討論,所以還需要一層for循環。 */ class Solution { public: vector<string> restoreIpAddresses(string s) { vector<string> result; Calc(0, s, result, ""); return result; } /* @func Calc:處理每部分part的遞歸函數 @param n:遞歸層數 @param s:切割後剩餘字符串 @param result: 存儲所有合法ip地址的容器 @param output: 存儲當前遞歸合法ip地址的變量*/ void Calc(int n, string s, vector<string>& result, string output) { // result 記得加& // n == 0,1,2,3 分別代表第一、二、三、四層遞歸 // n == 4 用於終止遞歸,如果s爲空,說明分割準確 if (n == 4) { if (s.empty()) result.push_back(output); } else { for (int k = 1; k <= 3; k++) { // 如果剩餘字符串不足以分割,則分割不合法 if (s.size() < k) break; int val = atoi(s.substr(0, k).c_str()); // 當出現以0開頭的part,如011, k != std::to_string(val).size() if (val <= 255 && k == std::to_string(val).size()) { Calc(n+1, s.substr(k), result, output+s.substr(0, k)+(n == 3? "" : ".")); } } } } };
補充,由於分割情況不多,這道題可以使用暴力求解法。
假設四個部分的長度分別爲a,b,c,d, 那麼我可以用四層循環得出所有分割組合,即滿足a+b+c+d = s.size(),然後分別檢測所有分割組合的合法性,將合法的存入vector容器中
代碼如下:
/* 2017/9/10 93. Restore_IP_Address 的遞歸寫法(暴力求解) 思路: ip地址分成四部分,每部分的長度最大爲3,這個數字很小, 要得到所有情況,可用暴力求解法 即四層for循環,得到所有符合的組合 a+b+c+d = s.size() 然後對組合分別進行檢驗,將符合的加入到容器中 */ class Solution { public: vector<string> restoreIpAddresses(string s) { vector<string> result; string output; for (int a = 1; a <= 3; a++) { for (int b = 1; b <= 3; b++) { for (int c = 1; c <= 3; c++) { for (int d = 1; d <= 3; d++) { if (a+b+c+d == s.size()) { int A = atoi(s.substr(0, a).c_str()); int B = atoi(s.substr(a, b).c_str()); int C = atoi(s.substr(a+b, c).c_str()); int D = atoi(s.substr(a+b+c).c_str()); if (A <= 255 && B <= 255 && C <= 255 && D <= 255) { output = std::to_string(A) + "." + std::to_string(B) + "." + std::to_string(C) + "." + std::to_string(D); // 如果有一個part出現以0開頭的,如011, // 那麼output.size()!=s.size() + 3 if (output.size() == s.size() + 3) result.push_back(output); } } } } } } return result; } };
以上內容皆爲本人觀點,歡迎大家提出批評和指導,我們一起探討!