Leetcode - Restore IP Addresses

My code:

import java.util.ArrayList;
import java.util.List;

public class Solution {
    public List<String> restoreIpAddresses(String s) {
        if (s == null)
            return null;
        ArrayList<String> result = new ArrayList<String>();
        if (s.length() < 4 || s.length() > 12)
            return result;
        restoreIpAddresses(s, "", 0, 0, 0, result);
        return result;
    }
    
    
    private void restoreIpAddresses(String s, String ip, int begin, int width, int level,
                                    ArrayList<String> result) {
        if (begin + width - 1 >= s.length())
            return;
        else if (level == 4) {
            if (s.length() - begin - width > 0)
                return;
            int ipPart = Integer.parseInt(s.substring(begin, begin + width));
            if (width == 3 && ipPart < 100)
                return;
            else if (width == 2 && ipPart < 10)
                return;
            else if (ipPart > 255)
                return;
            else {
                result.add(ip + Integer.toString(ipPart));
                return;
            }
        }
        else if (level == 0) {
            for (int i = 1; i < 4; i++)
                restoreIpAddresses(s, ip, begin + width, i, level + 1, result);
        }
        else {
            int residueIp = s.length() - begin - width;
            if (residueIp < 4 - level || residueIp > 3 * (4 - level))
                return;
            int ipPart = Integer.parseInt(s.substring(begin, begin + width));
            if (width == 3 && ipPart < 100)
                return;
            else if (width == 2 && ipPart < 10)
                return;
            else if (ipPart > 255)
                return;

            ip += Integer.toString(ipPart) + ".";
            for (int i = 1; i < 4; i++)
                restoreIpAddresses(s, ip, begin + width, i, level + 1, result);
        }
    }
    
    public static void main(String[] args) {
        Solution test = new Solution();
        System.out.println(test.restoreIpAddresses("101023"));
        
    }
}

My test result:

Paste_Image.png

这道题目和之前 Array里面的 permutation等等很像。不同的是,他只需要插入符合要求的字符串,不需要插入ArrayList, 所以不需要删除一些已经用过的东西。同时,他是分级的,当到达第四级时,就必须停止了。然后还有些corner case。
比如说,我规定这一级的 width = 3, 然后扫描出了, 017. 如果我调用Integer.parseInt 扫出来的就是17,这是对的。但是 017是错误的。应该排除。
还有width =2 , 08 这些也是错误的。
还有可以及时停止扫描来节省时间。比如当扫描到第二层时,如果后面的字符串长度只有1,那么不用操作了,这肯定是错的,后面还有两级呢。
如果后面的字符串长度 >6了,那也不需要扫描了,因为后面最多也就6位数字。
然后排除掉这些corner case后,程序就会跑的这么快了。
**
下面说下,我刚才才注意到的一个知识点。其实一开始我的代码不是这样的, 或者说有个细节不是这样的。也就是 ip + s.substring(begin, begin + width) 还是 ip + Integer.toString(ipPart); 其实两个方法达到的效果是相通的,但算法复杂度完全不同。下面粘上用 toString() 测试的图片。**

Paste_Image.png

具体string这一块其实有很多需要分析的。比如这里。
将一个 integer转换成string,怎么样更快?
Integer.toString(a); or String.valueOf(a); or String s = "" + a;
现在可以确定的是,最后一个很消耗资源。

Paste_Image.png

http://it.deepinmind.com/java/2014/03/24/java-string-performance.html

有时间再好好研究下 string 吧。里面讲究太多了。

**
总结: String, backtracing, Permutation thinking
**

Anyway, Good luck, Richardo!

My code:

import java.util.ArrayList;
import java.util.List;

public class Solution {
    public List<String> restoreIpAddresses(String s) {
        ArrayList<String> ret = new ArrayList<String>();
        if (s == null || s.length() < 4)
            return ret;
        helper(0, 1, s, new StringBuilder(), ret);
        return ret;
    }
    
    private void helper(int begin, int k, String s, StringBuilder ip, ArrayList<String> ret) {
        if (k == 4) {
            if (s.length() - begin > 3)
                return;
            if (s.charAt(begin) == '0' && s.length() - begin >= 2)
                return;
            int tmp = Integer.parseInt(s.substring(begin, s.length()));
            if (tmp > 255)
                return;
            int len = ip.length();
            ip.append(tmp);
            ret.add(ip.toString());
            ip.delete(len, ip.length());
        }
        else {
            for (int i = 1; i <= 3; i++) {
                if (s.length() - (begin + i) < (4 - k))
                    break;
                if (s.charAt(begin) == '0' && i >= 2)
                    break;
                int tmp = Integer.parseInt(s.substring(begin, begin + i));
                if (tmp > 255)
                    continue;
                int len = ip.length();
                ip.append(String.valueOf(tmp) + ".");
                helper(begin + i, k + 1, s, ip, ret);
                ip.delete(len, ip.length());
            }
        }
    }
    
    public static void main(String[] args) {
        Solution test = new Solution();
        System.out.println(test.restoreIpAddresses("010010"));
    }
}

这道题目还是挺烦的。
有几个corner case需要考虑。
首先,分成k < 4 和 k = 4两种情况。
k < 4 时,需要考虑剩余长度不够再做ip address,此时需要直接退出循环,break
k = 4 时,需要考虑剩余长度过长,不止3位了。此时也是退出dfs

需要考虑扫描出来的数字是否大于255.

需要考虑, 017 是不符合规定的,需要去除。
即任何以0开头的数字,除了0自己,都是违规的。

然后就差不多了。
Anyway, Good luck, Richardo!

My code:

import java.util.ArrayList;
import java.util.List;

public class Solution {
    public List<String> restoreIpAddresses(String s) {
        List<String> ret = new ArrayList<String>();
        if (s == null || s.length() == 0 || s.length() > 12) {
            return ret;
        }
        
        helper(0, s, new StringBuilder(), 0, ret);
        return ret;
    }
    
    private void helper(int begin, String s, StringBuilder ip, int level, List<String> ret) {
        if (begin >= s.length()) {
            if (level == 4) {
                ret.add(ip.deleteCharAt(ip.length() - 1).toString());
            }
            return;
        }
        int len = ip.length();
        for (int i = begin; i < begin + 3 && i < s.length(); i++) {
            String part = s.substring(begin, i + 1);
            int temp = Integer.parseInt(part);
            if (temp >= 256) {
                continue;
            }
            else if (part.charAt(0) == '0' && i > begin) {
                continue;
            }
            ip.append(part + ".");
            helper(i + 1, s, ip, level + 1, ret);
            ip.setLength(len);
        }
    }
}

自己写了出来,感觉比以前的代码简洁多了。
为什么呢?
仔细观察,发现我思考 backtracking 经常有个问题。
什么时候截止 backtracking
比如这里, level = 3 (0-3) 时,就可以停止了,
但我需要在 level = 3时加判断吗?
不该,否则代码会很复杂,和下部分代码也有很多重复。
我应该再下去一层,这才是底层。
所以backtracking 每一层的物理意义是,
这一层,我检验过了,ok, 没问题,下一层吧。
然后一层层下去。
如果这一层有问题,那么就返回。
如果走到最后一层,发现没有问题了,那么就将最终结果插入到容器中。

就是这么个过程。
word pattern 2 也是如此。

还有就是,backtracking 用 stringbuilder 时,可以用 setLength
之类的办法快速清除下一层给这层带来的变化。

还有个细节需要注意。当截下来的数字, > 255 或者,长度大于1却以0开头的话,都是无效的,直接 Ignore

Anyway, Good luck, Richardo! -- 09/19/2016

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,902评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,037评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,978评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,867评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,763评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,104评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,565评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,236评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,379评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,313评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,363评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,034评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,637评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,719评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,952评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,371评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,948评论 2 341

推荐阅读更多精彩内容

  • 背景 一年多以前我在知乎上答了有关LeetCode的问题, 分享了一些自己做题目的经验。 张土汪:刷leetcod...
    土汪阅读 12,716评论 0 33
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,566评论 18 139
  • My code: My test result: 这次作业比较有趣。可以科普下什么叫做 count and say...
    Richardo92阅读 385评论 0 2
  • 今天discussion课,讲的东西没想到就是我一直想学的。差一点没去上,因为之前几节课太无聊了。主要讲了 Col...
    Richardo92阅读 1,237评论 0 3
  • 在18、19世纪的工业革命后,人类社会的手工生产逐渐转向为机器制造,除了带来技术、经济的变革,在材料的运用上,也为...
    破点阅读 367评论 0 1