字符串题目

2018-01-24 20:19:48

  • 重复字符串匹配

问题描述:

问题求解:

使用brute force的方法求解,也就是依次比较,但是差别就是在A到末尾的时候循环从头开始继续进行比较。

    public int repeatedStringMatch(String A, String B) {
        for (int i = 0,j; i < A.length(); i++) {
            for (j = 0; j < B.length() && B.charAt(j) == A.charAt((i+j) % A.length()); j++);
            // i就是A中前面失配的个数,j.length = 部分1 + n * A.length + 部分2
            // i + j = i + 部分1 + n * A.length + 部分2 =(n + 1)* A.length + 部分2
            // 所以其实就是一个向上取整
            if(j == B.length()) return (i+j) / A.length() + ((i + j) % A.length() == 0 ? 0 : 1);
        }
        return -1;
    }

使用brute force的方法求解的运行效率是很低的,可以采用KMP算法加之改进。

    public int repeatedStringMatch(String A, String B) {
        int[] prefix = new int[B.length()];
        for (int i = 1, j = 0; i < B.length(); ) {
            if (B.charAt(i) == B.charAt(j)) prefix[i++] = ++j;
            else if (j == 0) i++;
            else j = prefix[j - 1];
        }
        for (int i = 0, j = 0; i < A.length(); i += j - prefix[j - 1], j = prefix[j - 1]) {
            while (j < B.length() && A.charAt((i + j) % A.length()) == B.charAt(j)) j++;
            if (j == B.length()) return (int)Math.ceil((double)(i + j) / A.length());
            if (j == 0) j++;
        }
        return -1;
    }

 

  • 字符数组压缩

问题描述:

问题举例:

 

问题求解:

使用双层while循环可以避免使用单层for循环末尾取不到的问题,并且代码显得更加紧凑。

    public int compress2(char[] chars) {
        int indexAns = 0;
        int index = 0;

        while(index < chars.length) {
            char currentChar = chars[index];
            int count = 0;
            while(index < chars.length && chars[index] == currentChar) {
                index++;
                count++;
            }
            chars[indexAns++] = currentChar;
            if(count != 1) {
                for(char c : Integer.toString(count).toCharArray()) {
                    chars[indexAns++] = c;
                }
            }
        }
        return indexAns;
    }

 

  • 回文子串

问题描述:

问题求解:

最初想到的解法就是DP,就是不断从长度1,2,3生成判断是否回文,计数。

    public int countSubstrings(String s) {
        int cnt = 0;
        boolean map[][] = new boolean[s.length()][s.length()];
        for (int i = 0; i < s.length(); i++) {
            map[i][i] = true;
            cnt++;
            if (i + 1 < s.length() && s.charAt(i) == s.charAt(i + 1)) {
                map[i][i + 1] = true;
                cnt++;
            }
        }
        for (int i = 2; i < s.length(); i++) {
            for (int j = 0; j < s.length() - i; j++) {
                if (s.charAt(j) == s.charAt(j + i) && map[j + 1][j + i - 1]) {
                    map[j][j+i] = true;
                    cnt++;
                }
                else {
                    map[j][j+i] = false;
                }
            }
        }
        return cnt;
    }

事实上,也可以使用递归的思路,不断的生成字串进行判断,这种方法也是非常巧妙的。

    int count = 0;

    public int countSubstrings2(String s) {
        if (s == null || s.length() == 0) return 0;

        for (int i = 0; i < s.length(); i++) { // i is the mid point
            extendPalindrome(s, i, i); // odd length;
            extendPalindrome(s, i, i + 1); // even length
        }

        return count;
    }

    private void extendPalindrome(String s, int left, int right) {
        while (left >=0 && right < s.length() && s.charAt(left) == s.charAt(right)) {
            count++; left--; right++;
        }
    }

 

  • Implement Magic Dictionary

问题描述:

问题求解:

使用Trie树可以很方便的进行求解,思路清晰。

public class MagicDictionary {
    class TrieNode {
        TrieNode[] child = new TrieNode[26];
        boolean isWord = false;
    }

    TrieNode root;

    /** Initialize your data structure here. */
    public MagicDictionary() {
        root = new TrieNode();
    }

    /** Build a dictionary through a list of words */
    public void buildDict(String[] dict) {
        for (String i : dict) {
            TrieNode cur = root;
            for (char j : i.toCharArray()) {
                if(cur.child[j - 'a'] == null) cur.child[j - 'a'] = new TrieNode();
                cur = cur.child[j - 'a'];
            }
            cur.isWord = true;
        }
    }

    /** Returns if there is any word in the trie that equals to the given word after modifying exactly one character */
    public boolean search(String word) {
        char[] s = word.toCharArray();
        for (int i = 0; i < s.length; i++) {
            for (char j = 'a'; j <= 'z'; j++) {
                if(j == s[i]) continue;
                char pre = s[i];
                s[i] = j;
                if (helper(s, root)) {
                    return true;
                }
                s[i] = pre;
            }
        }
        return false;
    }

    boolean helper(char[] s, TrieNode root) {
        TrieNode tmp = root;
        for (char c : s) {
            if(tmp.child[c - 'a'] == null) return false;
            tmp = tmp.child[c - 'a'];
        }
        return tmp.isWord;
    }
}

 

  • 判断子串

问题描述:

问题求解:

方法一、双指针,遍历t一遍,就可以得到结果,代码简洁,时间复杂度为O(n)。

    public boolean isSubsequence(String s, String t) {
        if (s.equals("")) return true;
        if (t.equals("")) return false;
        boolean res = false;
        int idxt = 0;
        int idxs = 0;
        char[] s1 = s.toCharArray();
        char[] t1 = t.toCharArray();
        for(;idxt < t1.length; idxt++) {
            if (t1[idxt] == s1[idxs]) idxs++;
            if (idxs == s1.length) {
                res = true;
                break;
            }
        }
        return res;
    }

方法二、follow up里提到,如果问题是一个t,多个s的情况下,使用上述的双指针,算法时间复杂度为O(kn),就不那么理想了。一般来说这种问题,可以使用预处理的方法进行改进。我们可以使用一个HashMap,将每个字符出现的index保存下来。对于每个query,遍历一遍s,对每个字符进行查看,如果Hash中没有的话,直接返回false,如果存在,则寻找其index,进行判断。

    public boolean isSubsequence(String s, String t) {
        if (s.equals("")) return true;
        if (t.equals("")) return false;
        HashMap<Character, List<Integer>> map = new HashMap<>();
        char[] t1 = t.toCharArray();
        char[] s1 = s.toCharArray();
        for (int i = 0; i < t1.length; i++) {
            if (!map.containsKey(t1[i])) map.put(t1[i], new ArrayList<Integer>());
            map.get(t1[i]).add(i);
        }
        int idx = 0;
        for (int i = 0; i < s1.length; i++) {
            if (!map.containsKey(s1[i])) return false;
            int k = Collections.binarySearch(map.get(s1[i]), idx);
            if (k < 0) k = -k - 1;
            if (k == map.get(s1[i]).size()) return false;
            idx = map.get(s1[i]).get(k) + 1;
        }
        return true;
    }

 

posted @ 2018-01-25 20:19  hyserendipity  阅读(344)  评论(0编辑  收藏  举报