【leetcode】复原IP

0、参考资料

分割回文子字符串

一、 题目描述

给定一个只包含数字的字符串 s ,用以表示一个 IP 地址,返回所有可能从 s 获得的 有效 IP 地址 。你可以按任何顺序返回答案。

有效 IP 地址 正好由四个整数(每个整数位于 0 到 255 之间组成,且不能含有前导 0),整数之间用 ‘.’ 分隔。

例如:“0.1.2.201” 和 “192.168.1.1” 是 有效 IP 地址,但是 “0.011.255.245”、“192.168.1.312” 和 “[email protected]” 是 无效 IP 地址。

输入:s = “25525511135”
输出:[“255.255.11.135”,“255.255.111.35”]

输入:s = “0000”
输出:[“0.0.0.0”]

二、 代码思路

摆明了就是回溯算法选择元素的条件:前导元素不能是0,选择的子串必须0-255 且没有特殊符号。跟87题有点相似的感觉

回溯算法本身作用就是选择元素,并根据所有选择的情况,形成一棵选择的的回溯搜索树,该树的每一条路径都是一种选择结果。

所以,我们来分析题目,在给定字符串中让我们选可能的IP地址组合,我们知道,IP地址其实就是由四块组成,说白了,就是让我们找不同的子串组合,这些不同的子串分别组合不同的四块,从而形成不同的IP地址。

那我们选择子串的时候,就能够很好的利用回溯算法,选择这个子串作为IP地址之一,看看形成的IP可行吗,然后如果我们不选这个子串作为IP(回溯),看看可行吗,这就是基于回溯的动态选择的特性,每一步都能判断,从而形成最终的结果集合。

语言描述总是不够,建议结合代码理解,结合上一道题找回文子串,就能发现这两题的回溯思想其实一摸一样,只不过选择元素的条件变了,前者是我选择的元素必须是回文串 ,后者的选择条件是我选择的子串必须是合理的IP(0 - 255,单个字符可为0,多个字符首位不能为0)。

基本上就是以这段代码为模板:

//回溯算法
    public void dfs(int cur) {
        if (cur == n) {
            res.add(new ArrayList(path));
            return;
        }
        for (int i = cur; i < n; i++) {
            if (dp[cur][i] == 1) {
                path.add(s.substring(cur, i + 1));
                //注意,这里的回溯是选择回文子串,而并非是选择单个字符。
                //所以,这里并不能是 cur + 1,而应该是i + 1.
                //原因就是:cur - i 已经成为一个子串了,那么证明该字串被选。
                //那么我们就应该从i + 1,开始再去选择下一个子串。
                //这个思想很重要。
                dfs(i + 1);
                path.remove(path.size() - 1);
            }
        }
    }
三、 代码题解
class Solution {
    private List<String> list = new ArrayList();
    private List<List<String>> resList = new ArrayList();
    private String s;
    public List<String> restoreIpAddresses(String s) {
        //摆明了就是回溯算法,选择元素的条件:前导元素不能是0,选择的子串必须0-255 且没有特殊符号
        //跟86题有点相似的感觉
        //先进行过滤操作,如果有负数和特殊字符就删掉,但是题目要求字符串s仅由数字组成,那么不可能有负数 (-1 -不是数字)
        if (s.length() > 12) {
            return new ArrayList();
        }
        this.s = s;
        dfs(0);
        List<String> res = new ArrayList();
        //生成结果集,就是转换一下格式没啥用
        for (int i = 0; i < resList.size(); i++) {
            StringBuilder sb = new StringBuilder();
            List<String> temp = resList.get(i);
            for (int j = 0; j < temp.size(); j++) {
                sb.append(temp.get(j));
            }
            sb.deleteCharAt(sb.length() - 1);
            res.add(new String(sb));
        }
        return res;
    }
    private void dfs(int pos) {
        if (pos == s.length() && list.size() == 4) {
            resList.add(new ArrayList(list));
            return;
        }
        //其实只需要遍历三个即可
        for (int i = pos; i < s.length(); i++) {
            //pos - i 这段字符串前导为0,但是该字符串长度不是1即并不是单个字符为0
            if (i - pos >= 1 && s.charAt(pos) == '0') {
                break;
            }
            //当子串长度超过 0 - 255时候也不选
            if (Integer.parseInt(s.substring(pos, i + 1)) > 255) {
                break;
            }
            list.add(s.substring(pos, i + 1) + ".");
            dfs(i + 1);
            list.remove(list.size() - 1);
        }
    }
}
//1.

你可能感兴趣的:(数据结构与算法,leetcode,回溯,算法)