93. 复原IP地址

https://leetcode-cn.com/tag/backtracking/

递归调用的一个重要特征-要返回 回溯

93. 复原IP地址

https://leetcode-cn.com/problems/restore-ip-addresses/ 

 93. 复原IP地址_第1张图片

三层for循环 

class Solution {
    private List res;

    public List restoreIpAddresses(String s) {
        res = new ArrayList<>();

        for (int i = 1; i < s.length(); i++) {
            String subStr = s.substring(0, i);
            if (!areYouOK(subStr)) {
                continue;
            }
            for (int j = i + 1; j < s.length(); j++) {
                String subStr02 = s.substring(i, j);
                if (!areYouOK(subStr02)) {
                    continue;
                }
                for (int k = j + 1; k < s.length(); k++) {
                    String subStr03 = s.substring(j, k);
                    String subStr04 = s.substring(k);
                    if (!areYouOK(subStr03) || !areYouOK(subStr04)) {
                        continue;
                    }
                    //System.out.println(subStr + "->" + subStr02 + "->" + subStr03+ "->" + subStr04);
                    if (howAreYou(subStr) && howAreYou(subStr02) && howAreYou(subStr03) && howAreYou(subStr04)) {
                        System.out.println(subStr + "->" + subStr02 + "->" + subStr03 + "->" + subStr04);
                        res.add(subStr + "." + subStr02 + "." + subStr03 + "." + subStr04);
                    }
                }
            }
        }
        return res;
    }

    /**
     * 检查数字是否合法
     * 不合法 010  00
     * 合法 0 10
     */
    private boolean howAreYou(String str) {
        if (str.length() >= 2 && str.charAt(0) == '0') {
            return false;
        }
        return true;
    }
    /**
     * 检查是否在 0~255
     */
    private boolean areYouOK(String str) {
        if (str.length() > 3) {
            return false;
        }
        int subIp = Integer.parseInt(str);
        if (subIp <= 255) {
            return true;
        }
        return false;
    }
//    /**
//     * 010010
//     * ["0.10.0.10","0.100.1.0"]
//     */
//    public static void main(String[] args) {
//        //new Solution().restoreIpAddresses("25525511135");
//        new Solution().restoreIpAddresses("010010");
//    }
}

递归回溯 

class Solution {
    //字符串长度
    private Integer strLen;
    //字符串
    private String str;
    //返回List
    private ArrayList res;
    
    public List restoreIpAddresses(String s) {
        strLen = s.length();
        res = new ArrayList<>();
        LinkedList tempLis = new LinkedList<>();
        str = s;
        backtrack(-1, 3, tempLis);
        return res;
    }

    /**
     * 255        255       11135
     *   |        |         |
     * prev_pos curr_pos max_pos
     * 
     * 遍历三个有效位置 curr_pos 以放置点。
     * 检查从上一个点到现在点中间的部分是否有效 :
     *      是 :
     *          放置该点。
     *          检查全部 3个点是否放好
     *              是 : 将结果添加到输出列表中。
     *              否 : 继续放下一个点 backtrack(curr_pos, dots - 1)。
     *       回溯,移除最后一个点。
     * @param prev_pos 上一个放置的点
     * @param dots     待放置点的数量
     */
    private void backtrack(int prev_pos, int dots, LinkedList tempLis) {
        int max_pos = Math.min(strLen - 1, prev_pos + 4);
        for (int curr_pos = prev_pos + 1; curr_pos < max_pos; curr_pos++) {
            String subStr = str.substring(prev_pos + 1, curr_pos + 1);
            if (areYouOK(subStr)) {
                tempLis.addLast(subStr);
                if (dots - 1 == 0) {//n-1个点即可判断结果了
                    //添加到结果集
                    addElement(curr_pos, tempLis);
                } else {
                    backtrack(curr_pos, dots - 1, tempLis);
                }
                //回溯
                tempLis.removeLast();
            }
        }
    }

    /**
     * 如果最后一个ip段合法就把这一组结果添加到List中
     *
     * @param curr_pos 最后一个点的位置
     */
    private void addElement(int curr_pos, LinkedList tempLis) {
        String subStr = str.substring(curr_pos + 1);
        //System.out.println(subStr);
        if (areYouOK(subStr)) {
            tempLis.addLast(subStr);
            res.add(String.join(".", tempLis));
            tempLis.removeLast();
        }
    }

    /**
     * 判断subNum是否在0~255之间,并且subNum不能是00、01等非法数字
     * @param subNum 一段ip地址
     */
    private boolean areYouOK(String subNum) {
        int subStrLen = subNum.length();
        if (subStrLen > 3) {
            return false;
        }
        if (subNum.charAt(0) != '0') {
            return Integer.parseInt(subNum) <= 255;
        } else {//str.charAt(0) == '0'
            return subStrLen == 1;
        }
    }
    //public static void main(String[] args) {
    //    //ArrayList list = new ArrayList<>();
    //    //list.add("255");
    //    //list.add("255");
    //    //list.add("11");
    //    //list.add("135");
    //    ////255.255.11.135
    //    //System.out.println(String.join(".", list));
    //
    //    //List reList = new Solution().restoreIpAddresses("010010");
    //    List reList = new Solution().restoreIpAddresses("25525511135");
    //    reList.forEach(System.out::println);
    //}
}

官方答案

class Solution {
    private int n;
    private String s;
    private LinkedList segments = new LinkedList();
    private ArrayList output = new ArrayList();
    /**
     * Check if the current segment is valid :
     * 1. less or equal to 255
     * 2. the first character could be '0'
     * only if the segment is equal to '0'
     */
    private boolean valid(String segment) {
        int m = segment.length();
        if (m > 3)
            return false;
        return (segment.charAt(0) != '0') ? (Integer.parseInt(segment) <= 255) : (m == 1);
    }

    /**
     * Append the current list of segments
     * to the list of solutions
     */
    private void update_output(int curr_pos) {
        String segment = s.substring(curr_pos + 1, n);
        if (valid(segment)) {
            segments.add(segment);
            output.add(String.join(".", segments));
            segments.removeLast();
        }
    }
    /**
     * The current dot curr_pos could be placed
     * in a range from prev_pos + 1 to prev_pos + 4.
     * The dot couldn't be placed
     * after the last character in the string.
     * 
     * @param prev_pos the position of the previously placed dot
     * @param dots     number of dots to place
     */
    private void backtrack(int prev_pos, int dots) {
        int max_pos = Math.min(n - 1, prev_pos + 4);
        for (int curr_pos = prev_pos + 1; curr_pos < max_pos; curr_pos++) {
            String segment = s.substring(prev_pos + 1, curr_pos + 1);
            if (valid(segment)) {
                segments.add(segment);  // place dot
                if (dots - 1 == 0)      // if all 3 dots are placed
                    update_output(curr_pos);  // add the solution to output
                else
                    backtrack(curr_pos, dots - 1);  // continue to place dots
                segments.removeLast();  // remove the last placed dot
            }
        }
    }
    public List restoreIpAddresses(String s) {
        n = s.length();
        this.s = s;
        backtrack(-1, 3);
        return output;
    }
}

131. 分割回文串 

https://leetcode-cn.com/problems/palindrome-partitioning/ 

93. 复原IP地址_第2张图片

class Solution {
    private List> res;
    public List> partition(String s) {
        res = new ArrayList<>();
        List value = new ArrayList<>();
        division(value, s, 0);
        return res;
    }
    private void division(List value, String sub, int index) {
        if (sub.length() == 0) {
            List item = new ArrayList<>();
            for (int i = 0; i < index; i++) {
                item.add(value.get(i));
            }
            res.add(item);
            return;
        }
        for (int i = 0; i < sub.length(); i++) {
            String divi = sub.substring(0, i + 1);
            String subStr = sub.substring(i + 1);
            if (isHuiWen(divi)) {
                value.add(index, divi);
                division(value, subStr, index + 1);
            }
        }
    }
    /**
     * str是否为回文串
     */
    private boolean isHuiWen(String str) {
        if (str.length() == 0) {
            return false;
        }
        int left = 0;
        int right = str.length() - 1;
        while (right >= left) {
            if (str.charAt(left) != str.charAt(right)) {
                return false;
            }
            right--;
            left++;
        }
        return true;
    }
}

加个缓存,快速判断回文字符串 

class Solution {
    private List> res;
    private HashSet cache;
    public List> partition(String s) {
        cache = new HashSet<>();
        res = new ArrayList<>();
        List value = new ArrayList<>();
        division(value, s, 0);
        return res;
    }

    private void division(List value, String sub, int index) {
        if (sub.length() == 0) {
            List item = new ArrayList<>();
            for (int i = 0; i < index; i++) {
                item.add(value.get(i));
            }
            res.add(item);
            return;
        }
        for (int i = 0; i < sub.length(); i++) {
            String divi = sub.substring(0, i + 1);
            String subStr = sub.substring(i + 1);
            if (cache.contains(divi)) {
                value.add(index, divi);
                division(value, subStr, index + 1);
            } else if (isHuiWen(divi)) {
                cache.add(divi);
                value.add(index, divi);
                division(value, subStr, index + 1);
            }
        }
    }
    /**
     * str是否为回文串
     */
    private boolean isHuiWen(String str) {
        if (str.length() == 0) {
            return false;
        }
        int left = 0;
        int right = str.length() - 1;
        while (right >= left) {
            if (str.charAt(left) != str.charAt(right)) {
                return false;
            }
            right--;
            left++;
        }
        return true;
    }
}

 截取字符串太耗时了

public class Solution {
    private List> res;
    public List> partition(String s) {
        res = new ArrayList<>();
        if (s.length() == 0) {
            return res;
        }
        LinkedList path = new LinkedList<>();
        backtracking(s, 0, path);
        return res;
    }
    /**
     * @param start 起始字符的索引
     * @param path  记录从根结点到叶子结点的路径
     */
    private void backtracking(String s, int start, LinkedList path) {
        if (start == s.length()) {
            res.add(new ArrayList<>(path));
            return;
        }
        for (int i = start; i < s.length(); i++) {
            // !!!截取字符串是消耗性能的,采用传子串索引的方式判断一个子串是否是回文子串
            if (!checkPalindrome(s, start, i)) {
                continue;
            }
            path.addLast(s.substring(start, i + 1));
            backtracking(s, i + 1, path);
            path.removeLast();
        }
    }
    /**
     * 判断回文串
     * @param left  子串的左边界,可以取到
     * @param right 子串的右边界,可以取到
     */
    private boolean checkPalindrome(String str, int left, int right) {
        while (left < right) {
            if (str.charAt(left) != str.charAt(right)) {
                return false;
            }
            left++;
            right--;
        }
        return true;
    }
}

 

//public static void main(String[] args) {
//    //System.out.println(new Solution().partition("aab"));
//    //[["c","d","d"],["c","dd"]]
//    System.out.println(new Solution().partition("cdd"));
//}

 

你可能感兴趣的:(oj刷题)