代码随想录算法训练营第二十八天|93.复原IP地址、78.子集、90.子集Ⅱ

文章介绍了如何使用回溯算法解决两类问题:一是从数字字符串中恢复有效的IP地址,二是找出整数数组的所有子集,包括幂集,并在处理重复元素时进行去重。此外,还提及了一维和二维差分的概念。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

day28 2023/02/28

一、复原IP地址

给定一个只包含数字的字符串,复原它并返回所有可能的 IP 地址格式。

有效的 IP 地址 正好由四个整数(每个整数位于 0 到 255 之间组成,且不能含有前导 0),整数之间用 '.' 分隔。

分析如下:

本题依旧可以抽象成树形结构

切割问题可以抽象为树型结构,如图:

93.复原IP地址

代码如下:

注明:复习C++中insert函数以及erase函数的用法/本题与计算机网络结合
 

class Solution {
public:
    vector<string> result;
    string s;
    bool isValidNet(string& str,int start,int end)
    {
       if(start>end) return false;
       if(str[start]=='0'&&start!=end)//0开头的不合法
       {
           return false;
       }
       int num=0;
       for(int i=start;i<=end;i++)
       {
           //遇到非数字字符直接返回错误
           if(str[i]<'0'||str[i]>'9')
             return false;
           //大于255也返回错误
           num=num*10+(str[i]-'0');
           if(num>255)
            return false;
       }
       return true;
    }
    void backtracking(string& s,int startIndex,int pointNum)//pointNum代表句点个数
    {
      if(pointNum==3)
      {
           if(isValidNet(s,startIndex,s.size()-1)==true)
          {
             result.push_back(s);
             return;
          }
      }
      for(int i=startIndex;i<s.size();i++)
      {
          if(isValidNet(s,startIndex,i)==true)
          {
             s.insert(s.begin()+i+1,'.');
             pointNum++;
             backtracking(s,i+2,pointNum);//注意这里是从i+2开始呢
             s.erase(s.begin()+i+1);
             pointNum--;
          }
          else break;
      }
    }
    vector<string> restoreIpAddresses(string s) {
      backtracking(s,0,0);
      return result;
    }
};

二、子集

给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。

分析如下:

以示例中nums = [1,2,3]为例把求子集抽象为树型结构,如下:

78.子集

代码如下:
 

class Solution {
public:
    vector<vector<int>> result;
    vector<int> path;
    void backtracking(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]);
           backtracking(nums,i+1);
           path.pop_back();
       }
    }
    vector<vector<int>> subsets(vector<int>& nums) {
        backtracking(nums,0);
        return result;
    }
};

三、子集Ⅱ

给定一个可能包含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。

说明:解集不能包含重复的子集。

分析如下:

理解“树层去重”和“树枝去重”非常重要

用示例中的[1, 2, 2] 来举例,如图所示: (注意去重需要先对集合排序

90.子集II

代码如下:

注意:去重需要排序

class Solution {
public:
    vector<vector<int>> result;
    vector<int> path;
    void backtracking(vector<int>& nums,int startIndex,vector<bool>& used)
    {
        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]&&used[i-1]==false)//去重操作想清楚
              continue;
            used[i]=true;
            path.push_back(nums[i]);
            backtracking(nums,i+1,used);
            used[i]=false;
            path.pop_back();
        }
    }
    vector<vector<int>> subsetsWithDup(vector<int>& nums) {
        vector<bool> used(nums.size(),false);
        sort(nums.begin(),nums.end());//排序别忘了
        
        backtracking(nums,0,used);
        return result;
    }
};

四、差分(自学内容)

一维差分:

给区间[l,r]中的每个数加上c:b[l]+=c , b[r-1]-=c

二维差分:

给以(x1,y1)为左上角,(x2,y2)为右下角的子矩阵中的所有元素加上c

s[x1,y1]+=c,s[x2+1,y1]-=c,s[x1,y2+1]-=c,s[x2+1,y2+1]+=c

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值