前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >算法细节系列(34):再见字符串(2)

算法细节系列(34):再见字符串(2)

作者头像
用户1147447
发布2019-05-26 09:51:37
2590
发布2019-05-26 09:51:37
举报
文章被收录于专栏:机器学习入门机器学习入门

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://cloud.tencent.com/developer/article/1434799

算法细节系列(34):再见字符串(2)

详细代码可以fork下Github上leetcode项目,不定期更新。

题目摘自leetcode:

Leetcode 071. Simplify Path

思路:

主要遇到三种符号

代码语言:javascript
复制
a. ".."
b. "."
c. "dir"

第一种情况模拟返回
第二种情况无作为
第三种情况进入文件夹下

主要是遇到"..",所以我们用stack来模拟这种返回上一层的操作

代码如下:

代码语言:javascript
复制
public String simplifyPath(String path) {
        Deque<String> stack = new ArrayDeque<>();
        char[] cs = path.toCharArray();
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < path.length(); ++i){
            if (cs[i] == '/'){
                if (i + 1 < path.length() && cs[i+1] == '/') i++;
                String dir = sb.toString();
                if (dir.isEmpty()) continue;
                if (dir.equals("..")){
                    if (!stack.isEmpty()) stack.pop();
                }
                else if (dir.equals(".")){
                }
                else{
                    stack.push(dir);
                }
                sb = new StringBuilder();
            }
            else{
                sb.append(cs[i]);
            }
        }
        if (sb.length() != 0){
            String dir = sb.toString();
            if (dir.equals("..")){
                if (!stack.isEmpty()) stack.pop();
            }
            else if (dir.equals(".")){
            }
            else{
                stack.push(dir);
            }
        }
        sb = new StringBuilder();
        while (!stack.isEmpty()){
            sb.append("/" + stack.pollLast());
        }
        return sb.toString().isEmpty() ? "/" : sb.toString();
    }

上面这代码够丑的,优化下,我用前一个”/”和下一个”/”作为读取数据的标志,所以在for循环结束还需要多判断一次。

我们可以用java自带的split方法进行简化:

代码语言:javascript
复制
public String simplifyPath(String path) {
        Deque<String> stack = new LinkedList<>();
        Set<String> omit = new HashSet<>(Arrays.asList("..",".",""));
        for (String dir : path.split("/")){
            if (dir.equals("..") && !stack.isEmpty()) stack.pop();
            else if (!omit.contains(dir)) stack.push(dir);
        }
        StringBuilder sb = new StringBuilder();
        while (!stack.isEmpty()) sb.append("/" + stack.pollLast());
        return sb.length() == 0 ? "/" : sb.toString();
    }

Leetcode 468. Validate IP Address

找规则解析就好了,corner case比较多,要有耐心,代码如下:

代码语言:javascript
复制
String IPv4 = "IPv4";
    String IPv6 = "IPv6";
    public String validIPAddress(String IP) {
        if (IP.isEmpty()) return "Neither";
        String ans = IP.contains(".") ? IPv4 : IPv6;
        if (ans.equals(IPv4)){
            ans = validIPv4(IP) ? ans : "Neither";
        }
        else{
            ans = validIPv6(IP) ? ans : "Neither";
        }
        return ans;
    }

    private boolean validIPv4(String IP){
        if (IP.charAt(IP.length()-1) == '.' || IP.charAt(0) == '.') return false;
        String[] nums = IP.split("\\.");
        if (nums.length != 4) return false;
        for (String num : nums){
            char[] c = num.toCharArray();
            if (num.isEmpty() || (c[0] == '0' && c.length != 1)) return false;
            int n = 0;
            int i = 0;
            while (i < c.length && c[i] >= '0' && c[i] <= '9'){
                n = 10 * n + c[i++] - '0';
            }
            if (!(n >= 0 && n <= 255) || i < c.length) return false;
        }
        return true;
    }

    private boolean validIPv6(String IP){
        if (IP.charAt(IP.length()-1) == ':' || IP.charAt(0) == ':') return false;
        String[] nums = IP.split(":");
        if (nums.length != 8) return false;
        for (String num : nums){
            if (num.isEmpty()) return false;
            char[] c = num.toCharArray();
            if (c.length >= 5) return false;
            for (int i = 0; i < c.length; ++i){
                if (! (c[i] >= '0' && c[i] <= '9' || c[i] >= 'a' && c[i] <= 'f' || c[i] >= 'A' && c[i] <= 'F'))
                    return false;
            }
        }
        return true;
    }

Leetcode 165. Compare Version Numbers

版本的比较,有点类似基数排序,很简单,先split(“.”),遇到大小相等的版本号(同一级别下),进入下一级别的比较。

代码如下:

代码语言:javascript
复制
public int compareVersion(String version1, String version2) {
        String[] v1 = version1.split("\\.");
        String[] v2 = version2.split("\\.");
        int min = Math.min(v1.length, v2.length);
        int i = 0;
        while (i < min && Integer.parseInt(v1[i]) == Integer.parseInt(v2[i])) i++;
        if (i == min){
            if (v1.length > v2.length){
                for (int j = i; j < v1.length; ++j){
                    if (Integer.parseInt(v1[j]) != 0) return 1;
                }
            }
            else if (v1.length < v2.length){
                for (int j = i; j < v2.length; ++j){
                    if (Integer.parseInt(v2[j]) != 0) return -1;
                }
            }
            return 0;
        }
        return Integer.parseInt(v1[i]) > Integer.parseInt(v2[i]) ? 1 : -1;
    }

代码简化思路:

代码语言:javascript
复制
version1 = "1.0.1.3.4.5"
version2 = "1.0"

可以看成:
version2 = "1.0.0.0.0.0"

代码如下:

代码语言:javascript
复制
public int compareVersion(String version1, String version2) {
        String[] v1 = version1.split("\\.");
        String[] v2 = version2.split("\\.");
        int max = Math.max(v1.length, v2.length);
        for (int i = 0; i < max; ++i){
            int num1 = i < v1.length ? Integer.parseInt(v1[i]) : 0;
            int num2 = i < v2.length ? Integer.parseInt(v2[i]) : 0;
            if (num1 < num2) return -1;
            if (num1 > num2) return 1;
        }
        return 0;
    }

Leetcode 068. Text Justification

贪心算法,比较细节,代码逻辑较复杂。

代码如下:(第一版)

代码语言:javascript
复制
    public List<String> fullJustify(String[] words, int maxWidth) {
        List<String> ans = new ArrayList<>();
        if (words.length == 0 || maxWidth == 0){
            ans.add("");
            return ans;
        }
        String res = greedy(words, maxWidth);
        while (!res.isEmpty()){
            ans.add(res);
            res = greedy(words, maxWidth);
        }
        return ans;
    }

    int pos = 0;
    private String greedy(String[] words, int maxWidth){
        if (pos == words.length) return "";
        String ans = words[pos];
        int cnt = ans.length();
        for (int i = pos + 1; i < words.length; ++i){
            if (cnt + words[i].length() + 1 <= maxWidth){
                ans += " " + words[i];
                cnt = ans.length();
                pos = i + 1;
            }
            else{
                pos = i;
                int space = maxWidth - cnt;
                String[] all = ans.split(" ");
                int len = all.length - 1;

                StringBuilder sb = new StringBuilder();
                if (len == 0){
                    sb.append(all[0]);
                    for (int k = 0; k < space; ++k){
                        sb.append(" ");
                    }
                    return sb.toString();
                }

                if (space % len == 0){
                    for (int k = 0; k < all.length; ++k){
                        sb.append(all[k] + " ");
                        for (int l = 0; l < space / len; ++l){
                            sb.append(" ");
                        }
                    }
                    return sb.toString().trim();
                }
                else{
                    int re = space % len;
                    int sp = space / len;
                    for (int k = 0; k < all.length; ++k){
                        sb.append(all[k] + " " + ((re != 0) ? " " : ""));
                        re = Math.max(--re,0);
                        for (int l = 0; l < sp; ++l){
                            sb.append(" ");
                        }
                    }
                    return sb.toString().trim();
                }
            }
        }

        pos = words.length;
        int space = maxWidth - cnt;
        String[] all = ans.split(" ");
        int len = all.length - 1;
        StringBuilder sb = new StringBuilder();
        if (len == 0){
            sb.append(all[0]);
            for (int k = 0; k < space; ++k){
                sb.append(" ");
            }
            return sb.toString();
        }

        sb = new StringBuilder(ans);
        for (int k = 0; k < space; ++k){
            sb.append(" ");
        }
        return sb.toString();
    }

for循环可以用while替代,一次找到需要组合的words,这样for中else的逻辑和for循环外的逻辑可以合并。

代码如下:(第二版本)

代码语言:javascript
复制
int pos = 0;
    private String greedy(String[] words, int maxWidth){
        if (pos == words.length) return "";
        int cnt = words[pos].length();
        int i = pos + 1;
        while (i < words.length && cnt + words[i].length() + 1 <= maxWidth){
            cnt += words[i++].length() + 1;
        }
        int space = maxWidth - cnt;
        int len = i - pos - 1;

        if (len == 0 || i == words.length){
            StringBuilder sb = new StringBuilder();
            for (int k = pos; k < i; ++k){
                sb.append(words[k] + " ");
            }
            sb.deleteCharAt(sb.length()-1);
            for (int k = 0; k < space; ++k){
                sb.append(" ");
            }
            pos = i;
            return sb.toString();
        }

        StringBuilder sb = new StringBuilder();
        if (space % len == 0){
            for (int k = pos; k < i; ++k){
                sb.append(words[k] + " ");
                for (int l = 0; l < space / len; ++l){
                    sb.append(" ");
                }
            }
            pos = i;
            return sb.toString().trim();
        }
        else{
            int re = space % len;
            int sp = space / len;
            for (int k = pos; k < i; ++k){
                sb.append(words[k] + " " + ((re != 0) ? " " : ""));
                re = Math.max(--re,0);
                for (int l = 0; l < sp; ++l){
                    sb.append(" ");
                }
            }
            pos = i;
            return sb.toString().trim();
        }
    }

单独开一个greedy方法也没谁了,还定义了全局变量pos,与其这样,不如放在一个方法内。

代码如下:(第三版本)

代码语言:javascript
复制
public List<String> fullJustify(String[] words, int maxWidth) {
        List<String> ans = new ArrayList<>();
        int pos = 0;
        while (pos < words.length){
            int cnt = words[pos].length();
            int i = pos + 1;
            while (i < words.length && cnt + words[i].length() + 1 <= maxWidth){
                cnt += words[i++].length() + 1;
            }
            int space = maxWidth - cnt;
            int len = i - pos - 1;
            StringBuilder sb = new StringBuilder();
            if (len == 0 || i == words.length){
                sb = new StringBuilder();
                for (int k = pos; k < i; ++k){
                    sb.append(words[k] + " ");
                }
                sb.deleteCharAt(sb.length()-1);
                for (int k = 0; k < space; ++k){
                    sb.append(" ");
                }
                pos = i;
                ans.add(sb.toString());
            }
            else{
                sb = new StringBuilder();
                if (space % len == 0){
                    for (int k = pos; k < i; ++k){
                        sb.append(words[k] + " ");
                        for (int l = 0; l < space / len; ++l){
                            sb.append(" ");
                        }
                    }
                    pos = i;
                    ans.add(sb.toString().trim());
                }
                else{
                    int re = space % len;
                    int sp = space / len;
                    for (int k = pos; k < i; ++k){
                        sb.append(words[k] + " " + ((re != 0) ? " " : ""));
                        re = Math.max(--re,0);
                        for (int l = 0; l < sp; ++l){
                            sb.append(" ");
                        }
                    }
                    pos = i;
                    ans.add(sb.toString().trim());
                }
            }
        }
        return ans;
    }

其实,space % len 都不需要单独出逻辑来,因为如果re为0就不append,如果re不为0,把这部分加上去就好了。

代码如下:(第四版本)

代码语言:javascript
复制
public List<String> fullJustify(String[] words, int maxWidth) {
        List<String> ans = new ArrayList<>();
        int pos = 0;
        while (pos < words.length){
            int cnt = words[pos].length();
            int i = pos + 1;
            while (i < words.length && cnt + words[i].length() + 1 <= maxWidth){
                cnt += words[i++].length() + 1;
            }
            int space = maxWidth - cnt;
            int len = i - pos - 1;
            StringBuilder sb = new StringBuilder();
            if (len == 0 || i == words.length){
                sb = new StringBuilder();
                for (int k = pos; k < i; ++k){
                    sb.append(words[k] + " ");
                }
                sb.deleteCharAt(sb.length()-1);
                for (int k = 0; k < space; ++k){
                    sb.append(" ");
                }
                ans.add(sb.toString());
            }
            else{
                sb = new StringBuilder();
                int re = space % len;
                int sp = space / len;
                for (int k = pos; k < i; ++k){
                    sb.append(words[k] + " " + ((re != 0) ? " " : ""));
                    re = Math.max(--re,0);
                    for (int l = 0; l < sp; ++l){
                        sb.append(" ");
                    }
                }
                ans.add(sb.toString().trim());
            }
            pos = i;
        }
        return ans;
    }

比较满意了。

Leetcode 151. Reverse Words in a String

用自带的java库函数做一把。

代码语言:javascript
复制
public String reverseWords(String s) {
        String[] words = s.trim().split(" +");
        Stack<String> stack = new Stack<>();
        for (String word : words){
            stack.push(word);
        }
        StringBuilder sb = new StringBuilder();
        while (!stack.isEmpty()){
            sb.append(stack.pop() + " ");
        }
        return sb.toString().trim();
    }

三行版本:

代码语言:javascript
复制
public String reverseWords(String s) {
    String[] words = s.trim().split(" +");
    Collections.reverse(Arrays.asList(words));
    return String.join(" ", words);
}
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017年06月13日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 算法细节系列(34):再见字符串(2)
    • Leetcode 071. Simplify Path
      • Leetcode 468. Validate IP Address
        • Leetcode 165. Compare Version Numbers
          • Leetcode 068. Text Justification
            • Leetcode 151. Reverse Words in a String
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档