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

来源:互联网 发布:ff14人族捏脸数据分享 编辑:程序博客网 时间:2024/05/22 01:36

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

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

题目摘自leetcode:

  • 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

Leetcode 071. Simplify Path

思路:
主要遇到三种符号

a. ".."b. "."c. "dir"第一种情况模拟返回第二种情况无作为第三种情况进入文件夹下主要是遇到"..",所以我们用stack来模拟这种返回上一层的操作

代码如下:

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方法进行简化:

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比较多,要有耐心,代码如下:

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(“\.”),遇到大小相等的版本号(同一级别下),进入下一级别的比较。

代码如下:

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;    }

代码简化思路:

version1 = "1.0.1.3.4.5"version2 = "1.0"可以看成:version2 = "1.0.0.0.0.0"

代码如下:

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

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

代码如下:(第一版)

    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循环外的逻辑可以合并。

代码如下:(第二版本)

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,与其这样,不如放在一个方法内。

代码如下:(第三版本)

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,把这部分加上去就好了。

代码如下:(第四版本)

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库函数做一把。

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();    }

三行版本:

public String reverseWords(String s) {    String[] words = s.trim().split(" +");    Collections.reverse(Arrays.asList(words));    return String.join(" ", words);}
阅读全文
0 0
原创粉丝点击