day24 力扣93.复原IP地址 力扣78.子集 力扣90.子集II

复原IP地址

有效 IP 地址 正好由四个整数(每个整数位于 0255 之间组成,且不能含有前导 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函数

cpp 复制代码
 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里。

cpp 复制代码
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--)。

cpp 复制代码
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过程在终止条件的前面(这样才有空集)

cpp 复制代码
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 一致,可看我昨天的解题思路。

cpp 复制代码
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;
    }
};