1、93复原IP地址
有效 IP 地址 正好由四个整数(每个整数位于 0 到 255 之间组成,且不能含有前导 0),整数之间用 ‘.’ 分隔。例如:“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”]
我的思路:131分割回文串
类似,这道题是分割IP地址。不是回文串的就要剪枝,这题同样不是有效的IP元素的也要剪枝。先写出多叉树,再写递归逻辑。遇到回溯的题先在纸上把问题画为多叉树演化一遍,不然很多细节想不到。
代码随想录:在原串上插入"."来分割,不新建串。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
| class Solution { public: void traverse(string &s,int startidx, int depth, string &path, vector<string> &res){ if(startidx == s.size()){ if(depth == 5){ res.emplace_back(path.substr(0,path.size()-1)); } return; } for(int i = startidx;i<s.size();i++){ if(depth == 4){ i = s.size()-1; } if(!isIPItem(s,startidx,i))continue; int sub_size = i-startidx+1; path.append(s,startidx,sub_size); path+="."; traverse(s,i+1,depth+1,path,res); path.pop_back(); path.erase(path.size()-sub_size,sub_size); } return; } bool isIPItem(string &s,int start, int end){ if(start != end && s[start]=='0')return false; if((end-start)>2)return false; cout << end-start <<endl; int ipitem = std::stoi(s.substr(start,end-start+1)); if(0 > ipitem || ipitem > 255)return false; return true; } vector<string> restoreIpAddresses(string s) { string path; vector<string> res; traverse(s,0,1,path,res); return res; } };
class Solution { private: vector<string> result; void backtracking(string& s, int startIndex, int pointNum) { if (pointNum == 3) { if (isValid(s, startIndex, s.size() - 1)) { result.push_back(s); } return; } for (int i = startIndex; i < s.size(); i++) { if (isValid(s, startIndex, i)) { s.insert(s.begin() + i + 1 , '.'); pointNum++; backtracking(s, i + 2, pointNum); pointNum--; s.erase(s.begin() + i + 1); } else break; } } bool isValid(const string& s, int start, int end) { if (start > end) { return false; } if (s[start] == '0' && start != end) { return false; } int num = 0; for (int i = start; i <= end; i++) { if (s[i] > '9' || s[i] < '0') { return false; } num = num * 10 + (s[i] - '0'); if (num > 255) { return false; } } return true; } public: vector<string> restoreIpAddresses(string s) { result.clear(); if (s.size() < 4 || s.size() > 12) return result; backtracking(s, 0, 0); return result; } };
|
2、78子集
给你一个整数数组 nums
,数组中的元素 互不相同 。返回该数组所有可能的
子集(幂集)。解集不能包含重复的子集。你可以按 任意顺序 返回解集。
我的思路:典型的组合问题。由于组合的个数没有限制,所以不需要往后剪枝。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| class Solution { public: void traverse(vector<int>& nums,int startidx,vector<int> &path,vector<vector<int>> &res){ res.emplace_back(path); if(startidx == nums.size())return;
for(int i = startidx;i < nums.size();i++){ path.emplace_back(nums[i]); traverse(nums,i+1,path,res); path.pop_back(); } } vector<vector<int>> subsets(vector<int>& nums) { vector<vector<int>> res; vector<int> path; traverse(nums,0,path,res); return res; } };
|
3、90子集II
给你一个整数数组 nums ,其中可能包含重复元素,请你返回该数组所有可能的
子集(幂集)。解集 不能 包含重复的子集。返回的解集中,子集可以按 任意顺序 排列。
我的思路:与78子集
不同,这题的候选元素有重复。候选元素重复要考虑树层去重和树枝去重两种情况。这里单个子集中的元素可以重复,例如[1,2,2],实际上两个2来自两个不同的元素。所以这题只用树层去重。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| class Solution { public: void traverse(vector<int>& nums, int startidx, vector<bool> &used, vector<int> &path,vector<vector<int>> &res){ res.emplace_back(path); if(startidx >= nums.size())return;
for(int i = startidx;i<nums.size();i++){ if(i > 0 && nums[i-1]==nums[i] && used[i-1]==false)continue; path.emplace_back(nums[i]); used[i] = true; traverse(nums,i+1,used,path,res); used[i] = false; path.pop_back(); } }
vector<vector<int>> subsetsWithDup(vector<int>& nums) { vector<int> path; vector<vector<int>> res; vector<bool> used(nums.size(),false);
std::sort(nums.begin(),nums.end()); traverse(nums,0,used,path,res); return res; } };
|
代码随想录算法训练第三十天|93复原IP地址|78子集|90子集II