回溯算法_字符分割

5520. 拆分字符串使唯一子字符串的数目最大

在这里插入图片描述
主要思路:

  1. 这一题是经典的dfs,你就不断的拆字符串,每一次拆到一个子串时加入unordered_set前,要检查是否重复,如果重复那就不加入,这个set起到了visited的作用
  2. 用一个变量去搜索可能的答案,节省空间,当然要用到回溯了
    代码如下:
class Solution
{
public:
  int ans;
  void solve(string &s, unordered_set<string> &st, int i, int deep)
  {
    if (i == s.size())
    {
      ans = max(ans, deep);
      return;
    }
    int n = s.size();
    // i是起点:从[0,size()),尾哨兵取不到,return了
    // j是截取的终点:从[1,size()]
    for (int j = i + 1; j <= n; ++j)
    {
      string sub = s.substr(i, j - i);
      if (st.find(sub) != st.end())
        continue;
      st.insert(sub);
      // 这个传参j传的好
      solve(s, st, j, deep + 1);
      st.erase(sub);
    }
  }
  int maxUniqueSplit(string s)
  {
    unordered_set<string> st;
    ans = 0;
    solve(s, st, 0, 0);
    return ans;
  }
};
93. 复原IP地址

在这里插入图片描述
主要思路:* 切割问题
切割问题

  1. 想到暴力搜索,字符串切割的方法是从周赛的题解上学习的
起点start:[0,size()), 终点end:[1,size()]
for(int end=start+1; end<=size();end++){
 str = s.substr(star,end-start);
}
  1. track是字符串回溯,有些特别,我用了substr()的技巧
// 93.复原IP地址
  vector<string> restoreIpAddresses(string s)
  {
    string track = "";
    vector<string> res;
    // 如果长度不够,不搜索
    if (s.length() < 4 || s.length() > 12)
    {
      return res;
    }
    int pointNum = 0;
    dfs11(track, res, s, 0, pointNum);
    return res;
  }

  void dfs11(string &track, vector<string> &res, string s, int start, int pointNum)
  {
    if (pointNum == 3)
    {
      // 逗点数量为3时,分隔结束
      // 判断第四段子字符串是否合法(最后一段),如果合法就放进result中

      if (isValid2(s.substr(start, s.size() - start)))
      {
        string t = track + s.substr(start, s.size() - start);
        res.push_back(t);
      }
      return;
    }

    // 从起始位置开始构造字段字符串串
    // start:[0,size() ) 起点
    // 截取终点 end: [1, size()]
    for (int end = start + 1; end <= s.length(); end++)
    {
      string tmp = s.substr(start, end - start);
      // 判断 [startIndex,i] 这个区间的子串是否合法
      if (!isValid2(tmp))
      {
        return;
      }
      // 合法,在i的后面插入一个逗点
      tmp += ".";
      int length = track.size();
      track += tmp;
      dfs11(track, res, s, end, pointNum + 1);
      // 回溯时删除
      track = track.substr(0, length); // 把tmp与.删除
    }
  }

  bool isValid2(string tmp)
  {
    int sum = 0;
    for (int i = 0; i < tmp.length(); i++)
    {
      if ('0' <= tmp[i] && tmp[i] <= '9')
      {
        sum = (tmp[i] - '0') + sum * 10;
      }
      else
      {
        return false;
      }
    }
    if (sum == 0 && tmp.size() != 1)
    {
      return false;
    }
    if (sum != 0 && tmp[0] == '0')
    {
      return false;
    }
    if (sum > 255 || sum < 0)
    {
      return false;
    }

    return true;
  }
131.分割回文串

在这里插入图片描述
主要题意:
就是不断切割字符子串,判断是否是回文串,判断回文串用一个while循环就可以了;

// 131.分割回文串
  vector<vector<string>> partition(string s)
  {
    // 用DFS, 回溯需要用在track,因为track是全局变量,每一个递归子树产生的结果在track push进res后,需要撤销选择
    vector<vector<string>> res;
    vector<string> track;
    if (0 == s.length())
      return res;
    backtrack(res, track, s, 0);
    return res;
  }

  void backtrack(vector<vector<string>> &res, vector<string> &track, string s, int start)
  {
    if (start == s.length())
    {
      res.push_back(track);
      return;
    }
    for (int end = start + 1; end <= s.length(); end++)
    {
      if (isPalind(s.substr(start, end - start)))
      {
        track.push_back(s.substr(start, end - start)); // 递归树第一层for循环 取 a ab aab
        backtrack(res, track, s, end);                 // 进入第一层for循环a的递归子树:a->ab
        track.pop_back();                              // 针对第一层for循环a pop掉 准备进入第一层for循环 ab的递归子树
      }
    }
  }

  bool isPalind(string s)
  {
    int left = 0;
    int right = s.length() - 1;
    while (left < right)
    {
      if (s[left] != s[right])
      {
        return false;
      }
      left++;
      right--;
    }
    return true;
  }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值