Leetcode No.93 recovery IP address (DFS)

1, Title Description

Given a string containing only numbers to represent an IP address, return all valid IP addresses that may be obtained from s. You can return answers in any order.

A valid IP address consists of exactly four integers (each integer is between 0 and 255 and cannot contain a leading 0). Integers are separated by '.'.

For example, "0.1.2.201" and "192.168.1.1" are valid IP addresses, but "0.011.255.245", "192.168.1.312" and "192 168@1.1 "Is an invalid IP address.

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"]

Tips: 0 <= s.length <= 3000 s consists of numbers only

2, Problem solving ideas

Backtracking algorithm is actually doing depth first traversal on a tree problem, so we need to convert the problem into a tree problem first. Here, please be sure to pick up the paper and pen, simulate how to generate the IP address through the specified string s, and draw the tree (this is very important).

I haven't finished the following picture (if it is finished, there are too many branches and leaves). Please try not to look at the picture I drew and try how to draw the tree diagram of this problem by yourself.

In the process of drawing a tree diagram, you will find that some branches and leaves are unnecessary. The operation of cutting unnecessary branches and leaves is pruning. In the code, it is generally implemented through break or continue and return (indicating recursive termination).

Analyze the pruning conditions (I only write some key points I think of, some of which can be thought of, but the coding is very complex, so I didn't write them):

1. At first, if the length of the string is less than 4 or more than 12, it must not be able to piece up the legal ip address (this can be generalized to the judgment of the intermediate node to produce pruning behavior);

2. Each node can choose only three interception methods: 1 bit, 2 bits and 3 bits. Therefore, each node can grow only 3 branches at most;

Judge whether it is a reasonable ip segment according to the intercepted string. There are many ways to write here. You can intercept it first, convert it to int, and then judge. My method is to convert it into int, which is a legal ip segment value, and then intercept it.

3. Since there are only 4 ip segments at most, this Trident tree has 4 layers at most. This condition is one of the recursive termination conditions;

4. Each node represents different stages of solving the problem. The required state variables are:

splitTimes: how many ip segments have been split; begin: the starting position of the intercepted ip segment; Path: record a path from the root node to the leaf node (a conventional variable of the backtracking algorithm, which is a stack); res: the variable that records the result set, general variable. Summary: the idea of this problem is not difficult, but the details are cumbersome. When to terminate recursively, how to manually intercept the string and convert it to int type, and how to find pruning in the intermediate node. These details need to be considered clearly during coding.

Some coding details are written in the code comments for your reference. There may be some missing places. Please give your comments. The code execution time I give is not very good.

3, Code

import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
import java.util.List;

public class Solution {

    public List<String> restoreIpAddresses(String s) {
        int len = s.length();
        List<String> res = new ArrayList<>();
        if (len > 12 || len < 4) {
            return res;
        }
        Deque<String> path = new ArrayDeque<>(4);
        dfs(s, len, 0, 4, path, res);
        return res;
    }

    // A variable is needed to record how many segments remain undivided
    private void dfs(String s, int len, int begin, int residue, Deque<String> path, List<String> res) {
        if (begin == len) {
            if (residue == 0) {//ip has been divided into 4 segments
                res.add(String.join(".", path));
            }
            return;
        }
        for (int i = begin; i < begin + 3; i++) {//Each ip segment has a maximum of 3 bits
            if (i >= len) {
                break;
            }
            if (residue * 3 < len - i) {//The remaining bits are too long. Even if each ip segment has 3 bits, it can't figure out the correct ip address. Pruning
                break;
            }
            if (judgeIpSegment(s, begin, i)) {
                String currentIpSegment = s.substring(begin, i + 1);
                path.addLast(currentIpSegment);
                dfs(s, len, i + 1, residue - 1, path, res);
                path.removeLast();//to flash back
            }
        }
    }
    //Monitor whether the slave left - > right can form an ip segment
    private boolean judgeIpSegment(String s, int left, int right) {
        int len = right - left + 1;
        if (len > 1 && s.charAt(left) == '0') {//0.011.255.245 invalid
            return false;
        }
        int res = 0;//Convert to integer
        while (left <= right) {
            res = res * 10 + s.charAt(left) - '0';
            left++;
        }
        return res >= 0 && res <= 255;
    }
}

4, Complexity analysis

We use SEG_COUNT=4 indicates the number of segments of the IP address.

Time complexity: O(3^4*n). Since the number of bits in each segment of the IP address will not exceed 3, we will only go deep into the next layer at most in each recursive layer. Due to SEG_COUNT=4, corresponding to the maximum number of layers of recursion, so the time complexity of recursion itself is O(3^4). If we recover an IP address that meets the requirements of the question, it takes O(n) time to add it to the answer array. Therefore, the total time complexity is O(3^4*n), where n is the length of the string s.

Spatial complexity: O(SEG_COUNT). Only the additional spatial complexity other than the one used to store the answer array is included here. Space used by recursion and maximum depth of recursion SEG_ Directly proportional to count. And in the above code, we only use SEG as an additional length_ The array segments of count stores IP addresses that have been searched, so the space complexity is O(SEG_COUNT).

Posted on Mon, 29 Nov 2021 02:28:44 -0500 by Qbasicboy