• 007.复原 IP 地址


    1.题目链接:

    93. 复原 IP 地址

    2.解题思路:

    2.1.题目要求:

    给定一串只包含数字的字符串s,返回所有让 s 构成 有效IP地址 的数字组合。

    有IP地址: 4个 [0,255] 范围内的数字 组成,并且整数之间用 " . " 分隔。

    注意:不能 重新排序或删除 s 中的任何数字。你可以按 任何 顺序返回答案。

    注意:数字除了数字 0 ,其他数字前面不能有前导 0 ,比如 01、011、0111。

    2.2.思路:

    用N叉树的思路做,终止条件是,当 s 已经得到了 4个 [0,255] 范围内的数字 就输入结果集,

    单层搜索,搜索的过程中不断判断搜集的 s 子串是不是符合 [0,255] 范围内的数字 的条件,符合就加个 . 在子串后面。

    2.3.回溯三部曲:

    2.3.1.确定回溯函数参数

    这题没path,直接分割 " . " 分割 s 可以startIndex: 搜索的起始位置,pointNum:添加逗点的数量,这个在终止条件上回说明。

    代码如下:

    1. vector result;// 记录结果
    2. void backtracking(string& s, int startIndex, int pointNum) {

    2.3.2.确定终止条件

    当 s 已经得到了 4个 [0,255] 范围内的数字 就输入结果集,在具体代码中用 pointNum 的数量有没有达到 3 来判断,达到 3 代表已经可以构成IP地址了,

    注意:到第三个 " . " 后面的字符,因为代码没有到for循环就需要判断了,需要额外判断到第三个 " . " 后面的字符是不是合法的,合法分割后的 s 输入 结果集,不合法就返回,接下来继续遍历或是结束。

    代码如下:

    1. if (pointNum == 3) { // 逗点数量为3时,分隔结束
    2. // 判断第四段子字符串是否合法,如果合法就放进result中
    3. if (isValid(s, startIndex, s.size() - 1)) {
    4. result.push_back(s);
    5. }
    6. return;
    7. }

     

    2.3.3.确定单层遍历逻辑

    搜索的过程中递归或回溯都需要更新 pointNum 的数量,同时不断判断分割的子串是不是合法的,合法的就分割,不合法就终止本层递归的for循环。

    向下一层递归的时候,因为 i 的后面加上 ' . ' ,所以 i + 1 变成了 i + 2。

    循环中 [ startIndex, i ] 这个区间是需要截取的子串,

    代码如下:

    1. for (int i = startIndex; i < s.size(); i++) {
    2. if (isValid(s, startIndex, i)) { // 判断 [startIndex,i] 这个区间的子串是否合法
    3. s.insert(s.begin() + i + 1 , '.'); // 在i的后面插入一个逗点
    4. pointNum++;
    5. backtracking(s, i + 2, pointNum); // 插入逗点之后下一个子串的起始位置为i+2
    6. pointNum--; // 回溯
    7. s.erase(s.begin() + i + 1); // 回溯删掉逗点
    8. } else break; // 不合法,直接结束本层循环
    9. }

     

    判断不合不合法的逻辑如下:

    主要是这三点,

    • 段位以0为开头的数字不合法
    • 段位里有非正整数字符不合法
    • 段位如果大于255了不合法

    代码如下:

    1. // 判断字符串s在左闭又闭区间[start, end]所组成的数字是否合法
    2. bool isValid(const string& s, int start, int end) {
    3. if (start > end) {
    4. return false;
    5. }
    6. if (s[start] == '0' && start != end) { // 0开头的数字不合法
    7. return false;
    8. }
    9. int num = 0;
    10. for (int i = start; i <= end; i++) {
    11. if (s[i] > '9' || s[i] < '0') { // 遇到非数字字符不合法
    12. return false;
    13. }
    14. num = num * 10 + (s[i] - '0');//字符串 转 数字 num= 10*num+(*str-'0');
    15. if (num > 255) { // 如果大于255了不合法
    16. return false;
    17. }
    18. }
    19. return true;
    20. }

    2.4.总代码:

    1. class Solution {
    2. private:
    3. vector result;// 记录结果
    4. // startIndex: 搜索的起始位置,pointNum:添加逗点的数量
    5. void backtracking(string& s, int startIndex, int pointNum) {
    6. if (pointNum == 3) { // 逗点数量为3时,分隔结束
    7. // 判断第四段子字符串是否合法,如果合法就放进result中
    8. if (isValid(s, startIndex, s.size() - 1)) {
    9. result.push_back(s);
    10. }
    11. return;
    12. }
    13. for (int i = startIndex; i < s.size(); i++) {
    14. if (isValid(s, startIndex, i)) { // 判断 [startIndex,i] 这个区间的子串是否合法
    15. s.insert(s.begin() + i + 1 , '.'); // 在i的后面插入一个逗点
    16. pointNum++;
    17. backtracking(s, i + 2, pointNum); // 插入逗点之后下一个子串的起始位置为i+2
    18. pointNum--; // 回溯
    19. s.erase(s.begin() + i + 1); // 回溯删掉逗点
    20. } else break; // 不合法,直接结束本层循环
    21. }
    22. }
    23. // 判断字符串s在左闭又闭区间[start, end]所组成的数字是否合法
    24. bool isValid(const string& s, int start, int end) {
    25. if (start > end) {
    26. return false;
    27. }
    28. if (s[start] == '0' && start != end) { // 0开头的数字不合法
    29. return false;
    30. }
    31. int num = 0;
    32. for (int i = start; i <= end; i++) {
    33. if (s[i] > '9' || s[i] < '0') { // 遇到非数字字符不合法
    34. return false;
    35. }
    36. num = num * 10 + (s[i] - '0');
    37. if (num > 255) { // 如果大于255了不合法
    38. return false;
    39. }
    40. }
    41. return true;
    42. }
    43. public:
    44. vector restoreIpAddresses(string s) {
    45. result.clear();
    46. if (s.size() < 4 || s.size() > 12) return result; // 算是剪枝了
    47. backtracking(s, 0, 0);
    48. return result;
    49. }
    50. };

    3.遇见的问题:

    这题是加了 " . " 就直接输入给result返回了?都不把除了合法的那四段之外的数字字符删除吗?

    题目意思理解错了,这一句话没注意到。

    "你 不能 重新排序或删除 s 中的任何数字。你可以按 任何 顺序返回答案。"

     

    for循环判断不合法break,直接循环就终止了吗?

    定义混淆了,是那个时候递归的for终止。

     

    那不用break,return可以吗?

    可以去试试。——可以

    什么时候会用上这个条件?

    01代码:

    1. if (start > end) {
    2. return false;
    3. }

     虽然这个一眼看上去确实,但是什么情况下会出现这种情况...不明白

     删掉这段代码后,测试案例中上图画圈的是没通过的,可以看出来是判断第三个 ' . ' 后面的子串符不符合题目要求的逻辑出错,这里start(startIndex传入),end( s.size() - 1传入)是需要01代码来返回false,start在 ' . ' 后面一位,end是 s.size() - 1 是等于 ' . ' 的位置的,

    也就是说满足 start > end 。

    还有这种操作?刚好三个点切割完,然后出现这种情况..好吧

    4.记录:

    学的效率有点慢,可能精力给内耗掉了。学累了?。

  • 相关阅读:
    再学二分查找
    Ansys Lumerical | 用于增强现实系统的表面浮雕光栅
    系统架构师--面向对象选择题
    24 mysql all 查询
    [附源码]java毕业设计课后作业提交系统关键技术研究与系统实现
    计算机网络——应用层协议(1)
    蓝桥杯跑步锻炼.c语言
    java面向对象(三)
    K8S哲学 - probe 探针
    基于STM32设计的智能货架(华为云IOT)(225)
  • 原文地址:https://blog.csdn.net/qq_70280303/article/details/128142066