LintCode字符串题总结

LintCode上tag标记为String的题目大概有30多道题。

408. Add Binary

在我之前写的一篇LintCode位运算题总结的博文里有提到,此处便不再赘述。


133. Longest Words

给定一个string数组,要求找到这个数组里最长的单词是哪些。最简单的方法就是两趟遍历,第一趟统计最长的单词长度,第二趟统计有哪些单词满足这个长度,则取出来。


422. Length of Last Word

给定一个包含空格和单词的字符串,要求出其中最后一个单词的长度。这道题用java很好做,直接用String的split函数,把空格隔开,然后返回最后一个下标对应的字符串的长度就行:

    public int lengthOfLastWord(String s) {
        String[] res = s.split(" ");
        if (res.length <= 0) {
            return 0;
        }
        return res[res.length - 1].length();
    }

157. Unique Characters

判断一个字符串里是否包含重复的字符。HashSet+一趟遍历即可。如果不让用HashSet,那就自己建立数组建Hash


158. Two Strings Are Anagrams

判断两个String是否是同字母异序词。HashMap+两趟遍历即可。

    public boolean anagram(String s, String t) {
        HashMap hash = new HashMap();
        for (int i = 0; i < s.length(); i++) {
            if (hash.containsKey(s.charAt(i))) {
                hash.put(s.charAt(i), hash.get(s.charAt(i)) + 1);
            } else {
                hash.put(s.charAt(i), 1);
            }
        }
        
        for (int i = 0; i < t.length(); i++) {
            if (hash.containsKey(t.charAt(i))) {
                hash.put(t.charAt(i), hash.get(t.charAt(i)) - 1);
            } else {
                return false;
            }
        }
        
        for (Character c : hash.keySet()) {
            if (hash.get(c) != 0) {
                return false;
            }
        }
        
        return true;
    }

55. Compare Strings

给定两个字符串A和B,判断A是否包含B里面的所有字符。跟上面那道题很类似,也是HashMap加两趟遍历搞定:

    public boolean compareStrings(String A, String B) {
        HashMap hash = new HashMap();
        for (int i = 0; i < A.length(); i++) {
            if (hash.containsKey(A.charAt(i))) {
                hash.put(A.charAt(i), hash.get(A.charAt(i)) + 1);
            } else {
                hash.put(A.charAt(i), 1);
            }
        }
        
        for (int i = 0; i < B.length(); i++) {
            if (hash.containsKey(B.charAt(i))) {
                hash.put(B.charAt(i), hash.get(B.charAt(i)) - 1);
                if (hash.get(B.charAt(i)) < 0) {
                    return false;
                }
            } else {
                return false;
            }
        }
        
        return true;
    }

420. Count and Say

题意是n=1时输出字符串1;n=2时,数上次字符串中的数值个数,因为上次字符串有1个1,所以输出11;n=3时,由于上次字符是11,有2个1,所以输出21;n=4时,由于上次字符串是21,有1个2和1个1,所以输出1211。依次类推,写个countAndSay(n)函数返回字符串。就用模拟的方法来就好,字符串的处理有点绕

    public String countAndSay(int n) {
        String s = "1";
        if (n == 1) {
            return s;
        }
        for (int i = 2; i <= n; i++) {
            String res = "";
            int index = 0;
            while (index < s.length()) {
                char now = s.charAt(index);
                int count = 1;
                while (index + 1 < s.length() && s.charAt(index + 1) == now) {
                    count++;
                    index++;
                }
                res = res + count;
                res = res + now;
                index++;
            }
            s = res;
        }
        return s;
    }


53. Reverse Words in a String

把一个String里包含的所有单词逆转,比如"the sky is blue"变为"blue is sky the","the sky is    blue"变为"blue is sky the"。多个空格当做一个空格来处理,开头和末尾不能包含空格。注意这道题在lintcode中直接用String.split(" ")是可以AC的,但是这是错的,因为同样一道题在leetcode中不能AC。所以得自己写一个类似split的函数来AC,用于处理多个空格连在一起的情况:

    private ArrayList findWord(String s) {
        ArrayList arr = new ArrayList();
        int index = 0;
        while (index < s.length()) {
            String word = "";
            while (index < s.length() && s.charAt(index) != ' ') {
                word += s.charAt(index);
                index++;
            }
            if (word.length() > 0) {
                arr.add(word);
            }
            index++;
        }
        return arr;
    } 
    public String reverseWords(String s) {
        ArrayList res = findWord(s);
        String word = "";
        for (int i = res.size() - 1; i > 0; i--) {
            word += res.get(i);
            word += " ";
        }
        if (res.size() > 0) {
            word += res.get(0);
        }
        return word;
    }

8. Rotate String

要求把一个字符串进行旋转操作,如下所示:

Given "abcdefg".

offset=0 => "abcdefg"
offset=1 => "gabcdef"
offset=2 => "fgabcde"
offset=3 => "efgabcd"
如果可以借助一个额外的数组,就可以用下面这种方法:

    public void rotateString(char[] str, int offset) {
        if (str == null || str.length == 0 || offset < 0) {
            return;
        }
        char[] res = new char[str.length];
        if (offset > str.length) {
            offset = offset % str.length;
        }
        for (int i = 0; i < str.length; i++) {
            if (i + offset < str.length) {
                res[i + offset] = str[i];
            } else {
                res[i + offset - str.length] = str[i];
            }
        }
        
        for (int i = 0; i < str.length; i++) {
            str[i] = res[i];
        }
    }
但是题目要求不能用到额外的空间,要就地进行。

212. Space Replacement

给定一个character的数组,要求把里面的所有空格都替换为%20,要求不用到额外的空间。方法就是先遍历一遍数有多少个空格,然后我就可以计算出全部替换之后的长度了,然后我再从后往前扫描逐个替换。这样就用了2趟遍历做到了:

    public int replaceBlank(char[] string, int length) {
        int count = 0;
        for (int i = 0; i < length; i++) {
            if (string[i] == ' ') {
                count++;
            }
        }
        int newLength = length + count * 2;
        int right = newLength - 1, left = length - 1;
        while (right >= 0 && left >= 0) {
            while (right >= 0 && left >= 0 && string[left] != ' ') {
                string[right--] = string[left--];
            }
            while (right >= 0 && left >= 0 && string[left] == ' ') {
                string[right--] = '0';
                string[right--] = '2';
                string[right--] = '%';
                left--;
            }
        }
        
        return newLength;
    }

415. Valid Palindrome

判断一个字符串是不是回文串,忽略大小写、空格、和其他字符。比如"A man, a plan, a canal: Panama" 是一个回文串。由于不允许使用额外的空间,所以得用双指针法从两端从中间进行扫描。

    private boolean isDigitOrLetter(String s, int pos) {
        if (s.charAt(pos) >= '0' && s.charAt(pos) <= '9' ) {
            return true;
        }
        if (s.charAt(pos) >= 'a' && s.charAt(pos) <= 'z' ) {
            return true;
        }
        if (s.charAt(pos) >= 'A' && s.charAt(pos) <= 'Z' ) {
            return true;
        }
        return false;
    }
    public boolean isPalindrome(String s) {
        s = s.toUpperCase();
        int start = 0, end = s.length() - 1;
        while (start < end) {
            if (isDigitOrLetter(s, start) == false) {
                 start++;
                 continue;
            }
            if (isDigitOrLetter(s, end) == false) {
                end--;
                continue;
            }
            if (s.charAt(start) != s.charAt(end)) {
                return false;
            } else {
                start++;
                end--;
            }
        }
        return true;
    }


13. strStr

要求自己实现找子串函数,给定一个目标字符串A和一个字符串B,要求返回B在A中出现的第一个位置,若B不是A的子串,则返回-1。这道题考察的不是KMP,而是考你两重循环能不能写对,bug free。还真别说,这道题要做到bug free还真挺难的,边界处理条件啥的。

首先思路肯定是2层循环遍历,外层循环是遍历source,但是不需要遍历到source的最后一个下标,只要下标小于source.length() - target.length() + 1就可以打止了。

然后内层循环是遍历target,思路就是如果能够遍历完整内层循环的话,就说明找到了匹配,这个时候外层循环的下标i就是出现的第一个位置了。

如果内部循环的遍历发现了不匹配,即source.charAt(i + j) != target.charAt(j)的时候,就跳出循环。

    public int strStr(String source, String target) {
        if (source == null || target == null) {
            return -1;
        }
        int i, j;
        for (i = 0; i < source.length() - target.length() + 1; i++) {
            for (j = 0; j < target.length(); j++) {
                if (source.charAt(i + j) != target.charAt(j)) {
                    break;
                }
            }
            if (j == target.length()) {
                return i;
            }
        }
        return -1;
    }


171. Anagrams

给定一个字符串数组,要求把里面所有的同字母异序词全部返回。

Given ["ab", "ba", "cd", "dc", "e"], return ["ab", "ba", "cd", "dc"].

    public List anagrams(String[] strs) {
        List res = new ArrayList();
        HashMap map = new HashMap();
        HashMap count = new HashMap();
        for (int i = 0; i < strs.length; i++) {
            char[] arr = strs[i].toCharArray();
            Arrays.sort(arr);
            String sorted = new String(arr);
            map.put(strs[i], sorted);
            if (count.containsKey(sorted)) {
                count.put(sorted, 1 + count.get(sorted));
            } else {
                count.put(sorted, 1);
            }
        }
        
        for (int i = 0; i < strs.length; i++) {
            String sorted = map.get(strs[i]);
            if (count.get(sorted) > 1) {
                res.add(strs[i]);
            }
        }
        return res;
    }
我是用两个HashMap搞定的,一个HashMap用于建立从原单词到有序单词的映射,比如abc、bac、cba都是映射到abc上,然后第二个HashMap用来统计abc出现的次数。然后第二次遍历的时候,我就对每个单词,查看它的映射出现的次数,如果出现超过1次,就说明有同字母异序词的存在,这个时候就把它加入结果。

427. Generate Parentheses

给定数字,要求生成n对合法的括号。一道经典的递归题,在CC150上第五版的9.6有详解。这道题总的来说有2种方法。

第一种:每找到一个左括号,就在其后面加一个完整的括号,最后再在开头加一个(),就形成了所有的情况,需要注意的是,有时候会出现重复的情况,所以我们用set数据结构,好处是如果遇到重复项,不会加入到结果中,最后我们再把set转为vector即可:

n=1: () 

n=2: (()) ()() 

n=3: (()()) ((())) ()(()) (())() ()()()

    private String insertInside(String s, int pos) {
        String left = s.substring(0, pos + 1);
        String right = s.substring(pos + 1);
        return left + "()" + right;
    }
    public ArrayList generateParenthesis(int n) {
        Set res = new HashSet();
        if (n == 0) {
            res.add("");
        } else {
            ArrayList pre = generateParenthesis(n - 1);
            for (String str : pre) {
                for (int i = 0; i < str.length(); i++) {
                    if (str.charAt(i) == '(') {
                        res.add(insertInside(str, i));
                    }
                }
                res.add("()" + str);
            }
        }
        return new ArrayList(res);
    }


但是这种方法比较耗时,需要在去重复上多花时间,算法不是特别高效。我们可以从头开始构建字符串以避免重复字符串的出现。通过添加左括号和右括号,同时保证构建的括号对是合法的。

第二种方法:在每层递归中选择添加左括号还是右括号。递归函数有2个重要的参数:leftParen、rightParen,分别代表可以继续添加的左括号数量、右括号数量。

递归终止条件:若两者都为0,则说明没有括号可以添加了,此时就可以把当前结果添加到返回结果,并且return

子递归:若leftParen大于0,则添加左括号并进入下层递归。若rightParen大于0,则添加右括号并进入下层递归。

需要注意的是,若递归中出现了leftParen大于rightParen是非法情况,此时需要直接return不作处理

参考:http://www.cnblogs.com/grandyang/p/4444160.html

    private void dfs(ArrayList res, int left, int right, String path) {
        if (left == 0 && right == 0) {
            res.add(path);
            return;
        }
        if (left > 0) {
            dfs(res, left - 1, right, path + "(");
        }
        if (right > 0 && left < right) {
            dfs(res, left, right - 1, path + ")");
        }
    }
    public ArrayList generateParenthesis(int n) {
        ArrayList res = new ArrayList();
        dfs(res, n, n, "");
        return res;
    }

418. Integer to Roman

整数转换为罗马数字,这道题就考你知不知道罗马数字的计数方式,记住就好:

    public String intToRoman(int n) {
        String res = "";
        String[] roman = {"M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"};
        int[] val = {1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1};

        for (int i = 0; i < 13; i++) {
            while (n >= val[i]) {
                res += roman[i];
                n -= val[i];
            }
        }
        
        return res;
    }


419. Roman to Integer

罗马数字转换为整数,就是上道题的逆过程,可以参考这篇博文:https://segmentfault.com/a/1190000002683379

记得从右往左读取判断,遇到最大的之前都累加,如果遇到小的就减去它:

    public int romanToInt(String s) {
        HashMap map = new HashMap();
        map.put('I', 1);
        map.put('V', 5);
        map.put('X', 10);
        map.put('L', 50);
        map.put('C', 100);
        map.put('D', 500);
        map.put('M', 1000);
        int res = 0;
        Character max = 'I';
        for (int i = s.length() - 1; i >= 0; i--) {
            if (map.get(s.charAt(i)) >= map.get(max)) {
                max = s.charAt(i);
                res += map.get(s.charAt(i));
            } else {
                res -= map.get(s.charAt(i));
            }
        }
        
        return res;
    }

78. Longest Common Prefix

给定一个字符串数组,要求找到他们的最长的公共前缀。假如那个字符串数组里面有ABCD四个String,有两种方法,

第一种是两两之间互相比较,先找到AB的公共前缀X,然后再把X去和C比较得到前缀Y,再把Y和D去比较得到最终的公共前缀。

第二种方法是先找到最短的String,最长的公共前缀的长度肯定不会超过最短的那个String的长度n,然后我就只要比较这些字符串的前n个字符就行了:

    public String longestCommonPrefix(String[] strs) {
        if (strs == null || strs.length == 0) {
            return "";
        }
        // 找到最短的单词的长度
        int n = Integer.MAX_VALUE;
        for (int i = 0; i < strs.length; i++) {
            if (strs[i].length() <= n) {
                n = strs[i].length();
            }
        }
        
        int index;
        for (index = 0; index < n; index++) {
            int j;
            for (j = 1; j < strs.length; j++) {
                if (strs[j].charAt(index) != strs[0].charAt(index)) {
                    break;
                }
            }
            if (j != strs.length) {
                break;
            }
        }

        return strs[0].substring(0, index);
    }


200. Longest Palindromic Substring

给定一个String,要求找到它的最长的回文子串。参考博文:http://blog.csdn.net/soszou/article/details/37312317

可以用中心扩展法,因为回文字符串是以中心轴对称的,所以如果我们从下标 i 出发,用2个指针向 i 的两边扩展判断是否相等,那么只需要对0到 n-1的下标都做此操作,就可以求出最长的回文子串。需要注意的是要对长度为偶数和长度为奇数的回文串分别做处理:

    private String findPalindrome(String s, int index) {
        int left = index, right = index;
        while (left >= 0 && right < s.length()) {
            if (s.charAt(left) == s.charAt(right)) {
                left--;
                right++;
            } else {
                break;
            }
        }
        return s.substring(left + 1, right);
    }
    private String findEven(String s, int pos1, int pos2) {
        int left = pos1, right = pos2;
        while (left >= 0 && right < s.length()) {
            if (s.charAt(left) == s.charAt(right)) {
                left--;
                right++;
            } else {
                break;
            }
        }
        return s.substring(left + 1, right);
    }
    public String longestPalindrome(String s) {
        String res = "";
        for (int i = 0; i < s.length(); i++) {
            String palindrome = findPalindrome(s, i);
            if (i + 1 < s.length()) {
                String even = findEven(s, i, i + 1);
                if (even.length() >= res.length()) {
                    res = even;
                }
            }
            if (palindrome.length() >= res.length()) {
                res = palindrome;
            }
        }
        return res;
    }


384. Longest Substring Without Repeating Characters

给定一个字符串,找到其中的一个最长的字串,使得这个子串不包含重复的字符。受到了这篇博文的启发:http://blog.csdn.net/feliciafay/article/details/16895637

使用left和right两个指针进行搜索,下标left代表候选的最长子串的开头,下标right代表候选的最长子串的结尾。

先假设left不动,那么在理想的情况下,我们希望可以一直右移right,直到right到达原字符串的结尾,此时right-left就构成了一个候选的最长子串。每次都维护一个max_length,就可以选出最长子串了。实际情况是,不一定可以一直右移right。

如果right下标对应的字符在之前已经出现过(假设它出现的上一个位置在k),并且这个k也在区间[left, right]的范围之内,那么就需要停止右移了。在下一次搜索中,left应该更新到k+1。(K用于记录这个元素上一次出现过的位置)。

举个栗子:abcdefc中,c1和c2重复了。那么下一次遍历,应该跨过出现重复的地方进行,否则找出来的候选串依然有重复字符,且长度还不如上次的搜索。所以下一次搜索,直接从c1的下一个字符d开始进行,也就是说,下一次搜寻中,left应该更新到k+1。

1)实现的时候,我们用一个HashMap用于记录每个字符上一次出现的位置。用双指针left、right来遍历和维护一个子串的区间。

2)当子串区间[left, right]里出现了重复元素时,我们就需要把那个重复元素在[left, right]区间中上一次出现的位置k拿出来,并把left重置为k+1。同时在HashMap中更新那个重复元素的位置,然后还需要处理的一个地方时不能让右指针right比left小,要让right指针保持在left的右边。如果此时right本来就在left右边,则继续让right往右挪1位。

3)如果子串区间[left, right]里没有出现了重复元素,那就一直让right自增扩大区间,并更新maxLength的信息。同时把每个元素出现的位置用HashMap保存下来。

有几个测例可以考虑一下:

aab

aabb

bbbbb

dvdf

an++--12a4

    public int lengthOfLongestSubstring(String s) {
        int left = 0, right = 0, max = 0;
        // HashMap用于记录字符上一次出现的位置
        HashMap map = new HashMap();
        while (right < s.length() && left < s.length()) {
            // 若有重复元素,则left标记为上一个重复元素 + 1
            if (map.containsKey(s.charAt(right)) && map.get(s.charAt(right)) >= left) {
                left = map.get(s.charAt(right)) + 1;
                map.put(s.charAt(right), right);
                if (right <= left) {
                    right = left + 1;
                } else {
                    right++;
                }
            } else {
                map.put(s.charAt(right), right);
                max = (right - left + 1) > max ? (right - left + 1) : max;
                right++;
            }
        }
        return max;
    }

425. Letter Combinations of a Phone Number


给定一个这样的手机数字键盘,要求输入某些数字后,返回所有可能的组合。比如输入23,得到的所有可能组合是["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"]

这种球所有组合的题目,十有八九得用DFS来做。

    private String[] map = {"", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"};
    private void dfs(ArrayList res, String path, String digits, int pos) {
        if (pos >= digits.length()) {
            res.add(path);
            return;
        }
        
        String s = map[digits.charAt(pos) - '0'];
        for (int i = 0; i < s.length(); i++) {
            path += String.valueOf(s.charAt(i));
            dfs(res, path, digits, pos + 1);
            path = path.substring(0, path.length() - 1);
        }
    }
    public ArrayList letterCombinations(String digits) {
        ArrayList res = new ArrayList();
        if (digits == null || digits.length() == 0) {
            return res;
        }
        dfs(res, "", digits, 0);
        return res;
    }
但是用String太耗费空间了,我们用StringBuilder这个类来做:

    private String[] map = {"", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"};
    private void dfs(ArrayList res, StringBuilder path, String digits, int pos) {
        if (pos >= digits.length()) {
            res.add(new String(path));
            return;
        }
        
        String s = map[digits.charAt(pos) - '0'];
        for (int i = 0; i < s.length(); i++) {
            path.append(s.charAt(i));
            dfs(res, path, digits, pos + 1);
            path.deleteCharAt(path.length() - 1);
        }
    }
    public ArrayList letterCombinations(String digits) {
        ArrayList res = new ArrayList();
        if (digits == null || digits.length() == 0) {
            return res;
        }
        dfs(res, new StringBuilder(), digits, 0);
        return res;
    }

421. Simplify Path

这是一道简化路径的题,给定一个Unix路径,要求简化后不改变原路径的意思。路径简化的依据是:

当字符串是空或者遇到”/../”,则需要返回一个"/"

当遇见"/a//b",则需要简化为"/a/b"

当遇到"//"则表示是本级目录,无需做任何操作。

当遇到"/./"则表示是本级目录,无需做任何特殊操作。

当遇到“/../"则需要返回上级目录,需检查上级目录是否为空。

这道题的核心思想是利用stack和string的split函数。首先利用split函数把原String分割开来,这样所有/这样的字符都没了,然后我们再把剩下的字符进行拼接,如果遇到".."就pop出之前的元素。否则就继续进行添加push。

需要注意的是要对 "/"、"//"、"///"这些情况进行处理。

    public String simplifyPath(String path) {
        String[] arr = path.split("/+");
        String res = "/";
        Stack stack = new Stack();
        for (int i = 0; i < arr.length; i++) {
            if (arr[i].equals("..")) {
                if (!stack.empty()) {
                    stack.pop();
                }
            } else if (!arr[i].equals(".") && !arr[i].equals("")) {
                stack.push(arr[i]);
            }
        }
        while (!stack.empty()) {
            res = "/" + stack.pop() + res;
        }
        if (res.length() > 1) {
            return res.substring(0, res.length() - 1);
        }
        return res;
    }

426. Restore IP Addresses

给定一个IP地址,要求返回它所有可能的合法的IP地址组合。比如给定:25525511135,得到的结果是:"255.255.11.135", "255.255.111.35"

这种求所有可能组合的题目,还是DFS来做。有点类似于String Permutation那道题。由于IP的每段最多只能为3位数,所以要注意一下这一点,每次循环最多生成3个子串,以避免无法进入下层子递归。

递归终止条件:path的长度为4的时候就进入终止条件。如果此时pos还没遍历到初始字符串的最后一位,这说明生成的IP地址是非法的,不能加入res中,直接return返回;如果此时pos遍历到了初始字符串的最后一位,就把这个IP地址加入res中并返回。

递归核心:递归核心部分就是从pos位置开始遍历字符串s,由于每个IP段最多为3位数,所以循环的次数应该在三次以内。每次循环,就把当前区间的子串给取出来,判断一下是不是合法的(0到255),如果合法就添加到路径中。需要对0进行处理,假设当前区间取到的子串是0、00、01这种,怎么处理?0是合法的,00、01肯定不是合法的。

然后还需要注意的是初始字符串的长度必须在4到12之间。

    private void dfs(ArrayList res, ArrayList path, String s, int pos) {
        if (path.size() == 4) {
            if (pos != s.length()) {
                return;
            }
            StringBuilder sb = new StringBuilder();
            for (String str : path) {
                sb.append(str);
                sb.append(".");
            }
            sb.deleteCharAt(sb.length() - 1);
            res.add(new String(sb));
            return;
        }
        for (int i = pos; i < s.length() && i <= pos + 2; i++) {
            String tmp = s.substring(pos, i + 1);
            if (!valid(tmp)) {
                continue;
            }
            path.add(tmp);
            dfs(res, path, s, i + 1);
            path.remove(path.size() - 1);
        }
    }
    private boolean valid(String s) {
        if (s.charAt(0) == '0') {
            return s.equals("0"); // to eliminate cases like "00", "01"
        }
        int num = Integer.parseInt(s);
        return num >= 0 && num <= 255;
    }
    public ArrayList restoreIpAddresses(String s) {
        ArrayList res = new ArrayList();
        if (s.length() < 4 || s.length() > 12) {
            return res;
        }
        dfs(res, new ArrayList(), s, 0);
        return res;
    }


417. Valid Number

参考了这篇博文:http://www.cnblogs.com/grandyang/p/4084408.html

这道题巨难,判断一个string是不是有效地数字表达式。思路:先移除前导零和后缀零,然后记录点和e的位置。再分情况讨论。

如果会正则表达式,这道题就巨简洁了:

    public boolean isNumber(String s) {
        if(s.trim().isEmpty()){  
            return false;  
        }  
        String regex = "[-+]?(\\d+\\.?|\\.\\d+)\\d*(e[-+]?\\d+)?";  
        if(s.trim().matches(regex)){  
            return true;  
        }else{  
            return false;  
        }
    }


九章上的标准答案如下:

    public boolean isNumber(String s) {
        // skip leading and trailing whitespaces
        s = s.trim();
        if (s == null || s.length() == 0) {
            return false;
        }
        int index = 0;
        // skip leading +/-
        if (s.charAt(index) == '+' || s.charAt(index) == '-') {
            index++;
        }
        boolean num = false; // is a digit
        boolean dot = false; // is a '.'
        boolean exp = false; // is a 'e'
        
        while (index < s.length()) {
            char c = s.charAt(index);
            if (Character.isDigit(c)) {
                num = true;
            } else if (c == '.') {
                if (dot || exp) return false;
                dot = true;
            } else if (c == 'e') {
                if (exp || num == false) return false;
                exp = true;
                num = false;
            } else if (c == '+' || c == '-') {
                if (s.charAt(index - 1) != 'e') return false; 
            } else {
                return false;
            }
            index++;
        }
        return num;
    }


54. String to Integer II

相当于自己实现一个atoi的函数,把string转换成int。这道题就考察你想到的corner case够不够全面。比如给定的字符串可能是“  123  ”,这个就得去掉首位的空格。比如给了你一个溢出int类型的数据:123123123123123,那你就只能返回int的最大值。假如给你一个" +-1111 ",那么这种非法的只能返回0.

考虑的情况足够多,就可以AC了:

    private boolean valid(Character c) {
        return c >= '0' && c <= '9';
    }
    public int atoi(String str) {
        // 用一个double来存储结果
        double res = 0;
        if (str == null || str.length() == 0) {
            return 0;
        }
        // 删除开头和末尾的空格
        str = str.trim();
        // 检查正负数
        boolean aboveZero = true;
        int i = 0;
        if (str.charAt(i) == '+') {
            i++;
        } else if (str.charAt(i) == '-') {
            i++;
            aboveZero = false;
        }
        
        // 计算值
        while(i < str.length() && valid(str.charAt(i))) {
            res = res * 10 + (str.charAt(i) - '0');
            i++;
        }
        if (aboveZero == false) {
            res = -res;
        }
        
        // 处理超过int最大长度的情况
        if (res > Integer.MAX_VALUE) {
            return Integer.MAX_VALUE;
        }
        if (res < Integer.MIN_VALUE) {
            return Integer.MIN_VALUE;
        }
        return (int) res;
    }


49. Sort Letters by Case

在 LintCode数组题总结 这篇博文中有,不再赘述。


10. String Permutation II

在 LintCode图论&搜索题总结 这篇博文中有,不再赘述。


180. Binary Representation

在 LintCode位运算题总结 这篇博文中有,不再赘述。


512. Decode Ways

118. Distinct Subsequences

119. Edit Distance

79. Longest Common Substring

107. Word Break

192. Wildcard Matching

154. Regular Expression Matching

430. Scramble String

这几道题的核心是动态规划,详情请参考我的LintCode动态规划总结题博文

你可能感兴趣的:(Algorithm)