LeetCode每日1题--复原IP地址

79 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第27天,点击查看活动详情

前言

算法的重要性不言而喻!区分度高!

现在学习的门槛低了,只有能上网每个人都可以学编程!培训班6个月就可以培养出来能干活的人,你怎么从这些人中脱颖而出?没错!就是学算法,学一些底层和基础的东西。

说的功利点是为了竞争,卷死对手。真心话说就是能提高自己的基础能力,为技术可持续发展做好充分的准备!!!

提前入门学习书籍:CPrimerPlus、大话数据结构

image-20220705103735001

刷题网站

代码随想录 (programmercarl.com)

leetcode

我是按照代码随想录提供的刷题顺序进行刷题的,大家也可以去刷leetcode最热200道,都可以

刷题嘛,最重要的就是坚持了!!!

画图软件

OneNote

这个要经常用,遇见不懂的流程的话就拿它画一画!

笔记软件

Typoral

题目

leetcode.cn/problems/re…

解析

复原IP地址和切割问题类似,只不过它有很多条件要注意,就是IP地址的规范 比如:IP段不能超过4段,每段的数字必须小于256

除此之外,题目要求,地址之间通过点来联系,所以我们还需要一个ponitNum来记录逗点的数量

回溯三部曲

  1. 递归参数

递归的参数中,start是必须的,因为不能重复切割,他负责遍历的时候我们应该从哪里进行切割

String s为目标字符串

number为ip段的数量

public void restoreIpAddressesHandler(String s, int start, int number) {}
  1. 递归终止的条件
  • 如果start等于s的长度并且ip段的数量是4,则加入结果集,并返回

  • 如果start等于s的长度但是ip段的数量不为4,或者ip段的数量为4但是start小于s的长度,则直接返回

if (start == s.length() && number == 4) {
        result.add(stringBuilder.toString());
        return;
}
if (start == s.length() || number == 4) {
        return;
}
  1. 单层搜索的逻辑
  • substring() 方法返回字符串的子字符串

  • 也就是在这个循环里,把所有可能的情况都包含进去了,比如ip段最大长度为3,每段处于0,255

  • ip段的长度最大是3,对应的代码就是i - start < 3

  • ip段的处于[0,255],对应的条件就是Integer.parseInt(s.substring(start,i+1))>=0,Integer.parseInt(s.substring(start, i + 1)) <= 255

  • 终止循环的条件就为i < s.length(),也就是说把传进来的字符串遍历完了

  • 如果ip段的长度大于1,并且第一位为0的话,continue。因为ip段中的第一段不能为0

  • 当stringBuilder里的网段数量小于3时,才会加点;如果等于3,说明已经有3段了,最后一段不需要再加点

for (int i = start; i < s.length() && i - start < 3 && Integer.parseInt(s.substring(start, i + 1)) >= 0 && Integer.parseInt(s.substring(start, i + 1)) <= 255; i++) {
    if (i + 1 - start > 1 && s.charAt(start) - '0' == 0) {
            continue;
    }
    
    stringBuilder.append(s.substring(start, i + 1));

    if (number < 3) {
            stringBuilder.append(".");
    }
    number++;
    
    restoreIpAddressesHandler(s, i + 1, number);
    
    number--;
    
    // 删除当前stringBuilder最后一个网段,注意考虑点的数量的问题
    stringBuilder.delete(start + number, i + number + 2);
}
}

完整代码

其实完整做下来还是有点难度的,没什么办法,多理解,多刷才行

//方法二:比上面的方法时间复杂度低,更好地剪枝,优化时间复杂度
class Solution {
// 存放结果
List<String> result = new ArrayList<String>();
// 拼接字符串
    StringBuilder stringBuilder = new StringBuilder();

    public List<String> restoreIpAddresses(String s) {
            restoreIpAddressesHandler(s, 0, 0);
            return result;
    }

    // number表示stringbuilder中ip段的数量
    public void restoreIpAddressesHandler(String s, int start, int number) {
        // 如果start等于s的长度并且ip段的数量是4,则加入结果集,并返回
        if (start == s.length() && number == 4) {
                result.add(stringBuilder.toString());
                return;
        }
        // 如果start等于s的长度但是ip段的数量不为4,或者ip段的数量为4但是start小于s的长度,则直接返回
        if (start == s.length() || number == 4) {
                return;
        }
            // 剪枝:ip段的长度最大是3,并且ip段处于[0,255]
    //substring() 方法返回字符串的子字符串。
    //也就是在这个循环里,把所有可能的情况都包含进去了,比如ip段最大长度为3,每段处于0,255
    // ip段的长度最大是3,对应的代码就是i - start < 3
    // ip段的处于[0,255],对应的条件就是Integer.parseInt(s.substring(start,i+1))>=0,Integer.parseInt(s.substring(start, i + 1)) <= 255
    // 终止循环的条件就为i < s.length(),也就是说把传进来的字符串遍历完了
    for (int i = start; i < s.length() && i - start < 3 && Integer.parseInt(s.substring(start, i + 1)) >= 0 && Integer.parseInt(s.substring(start, i + 1)) <= 255; i++) {
        // 如果ip段的长度大于1,并且第一位为0的话,continue。因为ip段中的第一段不能为0
        if (i + 1 - start > 1 && s.charAt(start) - '0' == 0) {
                continue;
        }
//拼接
        stringBuilder.append(s.substring(start, i + 1));
        // 当stringBuilder里的网段数量小于3时,才会加点;如果等于3,说明已经有3段了,最后一段不需要再加点
        if (number < 3) {
                stringBuilder.append(".");
        }
        number++;
        restoreIpAddressesHandler(s, i + 1, number);
        number--;
        // 删除当前stringBuilder最后一个网段,注意考虑点的数量的问题
        stringBuilder.delete(start + number, i + number + 2);
    }
}
}