zoukankan      html  css  js  c++  java
  • [LeetCode] 93. Restore IP Addresses

    Given a string s containing only digits, return all possible valid IP addresses that can be obtained from s. You can return them in any order.

    A valid IP address consists of exactly four integers, each integer is between 0 and 255, separated by single dots and cannot have leading zeros. For example, "0.1.2.201" and "192.168.1.1" are valid IP addresses and "0.011.255.245", "192.168.1.312" and "192.168@1.1" are invalid IP addresses. 

    Example 1:

    Input: s = "25525511135"
    Output: ["255.255.11.135","255.255.111.35"]
    

    Example 2:

    Input: s = "0000"
    Output: ["0.0.0.0"]
    

    Example 3:

    Input: s = "1111"
    Output: ["1.1.1.1"]
    

    Example 4:

    Input: s = "010010"
    Output: ["0.10.0.10","0.100.1.0"]
    

    Example 5:

    Input: s = "101023"
    Output: ["1.0.10.23","1.0.102.3","10.1.0.23","10.10.2.3","101.0.2.3"]

    Constraints:

    • 0 <= s.length <= 3000
    • s consists of digits only.

    复原IP地址。

    题意是给一个字符串,请你把它还原成IP地址。

    首先明确一下一个valid的IP地址,是需要满足如下几个条件的

    • 只能分成4段
    • 每段最多只有3个digit
    • 每段是一个不超过255的整数,且这个数字不是0的话,是不能以0开头的(比如01这种就是错的)

    两种思路,一是暴力解;二是回溯backtracking。

    首先给出暴力解。既然要满足如上几个条件,那么暴力解是需要把input分成三段的,每段的长度介于[1, 3]之间,同时需要一个helper函数判断是否是一个valid的segment,valid的条件就是如上几条。代码如下,

    时间O(n^3)

    空间O(1)

    Java实现

     1 class Solution {
     2     public List<String> restoreIpAddresses(String s) {
     3         List<String> res = new ArrayList<>();
     4         int n = s.length();
     5         for (int i = 0; i < 3; i++) {
     6             for (int j = i + 1; j < i + 4; j++) {
     7                 for (int k = j + 1; k < j + 4; k++) {
     8                     if (i < n && j < n && k < n) {
     9                         String tmp1 = s.substring(0, i + 1);
    10                         String tmp2 = s.substring(i + 1, j + 1);
    11                         String tmp3 = s.substring(j + 1, k + 1);
    12                         String tmp4 = s.substring(k + 1);
    13                         if (helper(tmp1) && helper(tmp2) && helper(tmp3) && helper(tmp4)) {
    14                             res.add(tmp1 + '.' + tmp2 + '.' + tmp3 + '.' + tmp4);
    15                         }
    16                     }
    17                 }
    18             }
    19         }
    20         return res;
    21     }
    22 
    23     private boolean helper(String tmp) {
    24         if (tmp == null || tmp.length() == 0 || tmp.length() > 3 || (tmp.charAt(0) == '0' && tmp.length() > 1)
    25                 || Integer.parseInt(tmp) > 255) {
    26             return false;
    27         }
    28         return true;
    29     }
    30 }

    接下来是回溯,我参考了这个帖子

    时间O(1) - 有效的IP地址的个数是有限的

    空间O(1) - 有效的IP地址的个数是有限的

    Java实现

     1 class Solution {
     2     public List<String> restoreIpAddresses(String s) {
     3         List<String> ans = new ArrayList<>();
     4         if (s == null || s.length() == 0) {
     5             return ans;
     6         }
     7         // 回溯
     8         helper(s, 0, new ArrayList<>(), ans);
     9         return ans;
    10     }
    11 
    12     // 中间两个参数解释:pos-当前遍历到 s 字符串中的位置,cur-当前存放已经确定好的 ip 段的数量
    13     private void helper(String s, int pos, List<String> cur, List<String> ans) {
    14         if (cur.size() == 4) {
    15             // 如果此时 pos 也刚好遍历完整个 s
    16             if (pos == s.length()) {
    17                 // join 用法:例如 [[255],[255],[111],[35]] -> 255.255.111.35
    18                 ans.add(String.join(".", cur));
    19             }
    20             return;
    21         }
    22 
    23         // ip 地址每段最多有三个数字
    24         for (int i = 1; i <= 3; i++) {
    25             // 如果当前位置距离 s 末尾小于 3 就不用再分段了,直接跳出循环即可。
    26             if (pos + i > s.length()) {
    27                 break;
    28             }
    29             // 将 s 的子串开始分段
    30             String segment = s.substring(pos, pos + i);
    31             // 剪枝条件:段的起始位置不能为 0,段拆箱成 int 类型的长度不能大于 255
    32             if (segment.startsWith("0") && segment.length() > 1 || (i == 3 && Integer.parseInt(segment) > 255)) {
    33                 continue;
    34             }
    35             // 符合要求就加入到 cur 数组中
    36             cur.add(segment);
    37             // 继续递归遍历下一个位置
    38             helper(s, pos + i, cur, ans);
    39             // 回退到上一个元素,即回溯
    40             cur.remove(cur.size() - 1);
    41         }
    42     }
    43 }

    另一种回溯实现

     1 class Solution {
     2     public List<String> restoreIpAddresses(String s) {
     3         List<String> res = new ArrayList<>();
     4         if (s == null || s.length() > 12 || s.length() < 4) {
     5             return res;
     6         }
     7         helper(res, s, "", 0, 0);
     8         return res;
     9     }
    10 
    11     private void helper(List<String> res, String s, String cur, int index, int count) {
    12         if (count > 4) {
    13             return;
    14         }
    15         if (count == 4 && index == s.length()) {
    16             res.add(cur);
    17             return;
    18         }
    19         for (int i = 1; i < 4; i++) {
    20             if (index + i > s.length()) {
    21                 break;
    22             }
    23             String temp = s.substring(index, index + i);
    24             if (temp.startsWith("0") && temp.length() > 1) {
    25                 continue;
    26             }
    27             if (i == 3 && Integer.parseInt(temp) >= 256) {
    28                 continue;
    29             }
    30             helper(res, s, cur + temp + (count == 3 ? "" : "."), index + i, count + 1);
    31         }
    32     }
    33 }

    LeetCode 题目总结

  • 相关阅读:
    mysql数据库——特殊sql语句整理之修改表结构
    mysql数据库引擎——MyISAM,InnoDB
    Golang程序性能分析
    Docker基本操作
    go module
    Docker基础原理
    基于zookeeper或redis实现分布式锁
    漫谈微服务
    快速排序
    设计模式泛谈
  • 原文地址:https://www.cnblogs.com/cnoodle/p/12813072.html
Copyright © 2011-2022 走看看