day24 力扣93.复原IP地址 力扣78.子集 力扣90.子集II
复原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 地址。给定一个只包含数字的字符串
s
,用以表示一个 IP 地址,返回所有可能的有效 IP 地址,这些地址可以通过在s
中插入'.'
来形成。你 不能 重新排序或删除s
中的任何数字。你可以按 任何 顺序返回答案。示例 1:
输入:s = "25525511135" 输出:["255.255.11.135","255.255.111.35"]示例 2:
输入:s = "0000" 输出:["0.0.0.0"]示例 3:
输入:s = "101023" 输出:["1.0.10.23","1.0.102.3","10.1.0.23","10.10.2.3","101.0.2.3
首先我们要搞清楚,什么样的ip地址是有效的
主要考虑到如下三点:
- 段位以0为开头的数字不合法
- 段位里有非正整数字符不合法
- 段位如果大于255了不合法
那么我们就可以isValid函数
bool isVaild(const string& s, int start, int end){if(start > end)return false;if(s[start]== '0'&&start!=end)return false;int sum = 0;for(int i = start;i<=end;i++){if(s[i]<'0'||s[i]>'9')return false;sum = sum*10+(s[i]-'0');}if(sum>255)return false;return true;}
我们在完成result的一次push_back,要进行四次的isValid判断。每次判断仅为一个区间内。注意把一个字符串的数转变成int类型的过程。这里注意到我们在主函数要考虑s的大小,如果s.size()小于4或大于12,那么我们直接返回空result.(因为大小不在4到12的话,就无法构成合理ip地址,且大于12的时候我们isValid函数中sum可能会溢出)
然后就是我们的回溯三部曲分析了。
第一步:确定返回值和参数。返回值不说,参数除了基本的,还要加上pointSum,即s字符串现在已有的'.'(为什么第二步说) 。
第二步:确定终止条件。如果要构成合理ip地址,那么就会出现3个‘.’('.'前区间均合法),也就是我们只需要判断最后一个区间是否合法,即可将这个ip加在result里。
if(pointSum == 3){if(isVaild(s,startIndex,s.size()-1)){result.push_back(s);} return;}
第三步:单层搜索的过程。我们直接判断startIndex到i的区间是否合法,如果不合法,直接break掉循环(因为只不合法,那就不考虑)
在合法的情况下,插入‘.’(insert库函数),让pointNum++,递归(这里要i+2,因为我们insert了一个符号),回溯 (erase库函数,pointNum--)。
class Solution {
public:vector<string> result;int pointSum = 0;bool isVaild(const string& s, int start, int end){if(start > end)return false;if(s[start]== '0'&&start!=end)return false;int sum = 0;for(int i = start;i<=end;i++){if(s[i]<'0'||s[i]>'9')return false;sum = sum*10+(s[i]-'0');}if(sum>255)return false;return true;}void backtracking(string& s,int startIndex,int pointSum){if(pointSum == 3){if(isVaild(s,startIndex,s.size()-1)){result.push_back(s);} return;}for(int i = startIndex;i<s.size();i++){if(isVaild(s,startIndex,i)){s.insert(s.begin()+i+1,'.');pointSum++;backtracking(s,i+2,pointSum);s.erase(s.begin()+i+1);pointSum--;}else break;}}vector<string> restoreIpAddresses(string s) {if (s.size() < 4 || s.size() > 12) return result; backtracking(s,0,0);return result;}
};
子集
给你一个整数数组
nums
,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。
示例 1:
输入:nums = [1,2,3] 输出:[[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]示例 2:
输入:nums = [0] 输出:[[],[0]]提示:
1 <= nums.length <= 10
-10 <= nums[i] <= 10
nums
中的所有元素 互不相同
这题就很简单,只要考虑到回溯的终止条件是 遇见叶子节点就return, 且本题的result的push_back过程在终止条件的前面(这样才有空集)
class Solution {
public:vector<int> path;vector<vector<int>> result;void backtracikng(vector<int>& nums,int startIndex){result.push_back(path);if(startIndex == nums.size())return ;for(int i = startIndex;i<nums.size();i++){path.push_back(nums[i]);backtracikng(nums,i+1);path.pop_back();}}vector<vector<int>> subsets(vector<int>& nums) {backtracikng(nums,0);return result;}
};
子集II
给你一个整数数组
nums
,其中可能包含重复元素,请你返回该数组所有可能的 子集(幂集)。解集 不能 包含重复的子集。返回的解集中,子集可以按 任意顺序 排列。
示例 1:
输入:nums = [1,2,2] 输出:[[],[1],[1,2],[1,2,2],[2],[2,2]]示例 2:
输入:nums = [0] 输出:[[],[0]]提示:
1 <= nums.length <= 10
-10 <= nums[i] <= 10
这道题就是子集的前提下数组存在重复情况,我们要排序去重处理,本题思路 组合总和II 一致,可看我昨天的解题思路。
class Solution {
public:vector<int> path;vector<vector<int>> result; void backtracking(vector<int>& nums, int startIndex,vector<bool>& isUsed){result.push_back(path);if(startIndex==nums.size())return;for(int i = startIndex;i<nums.size();i++){if(i>0&&nums[i]==nums[i-1]&&isUsed[i-1]==false)continue;path.push_back(nums[i]);isUsed[i]=true;backtracking(nums,i+1,isUsed);path.pop_back();isUsed[i]=false;}}vector<vector<int>> subsetsWithDup(vector<int>& nums) {vector<bool> isUsed(nums.size(),false) ;sort(nums.begin(),nums.end());backtracking(nums,0,isUsed);return result;}
};