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