Copy
// 自己写了一遍
public List<String> findWords(String str, List<String> dict) {
List<String> res = new ArrayList<>();
if (str == null || str.length() == 0 || dict == null || dict.isEmpty()) {
return res;
}
// 1. create table for next step
// we only has 26 chars
int[][] nextStep = findNextStep(str);
// 2. loop and check subsequnces
for (String word : dict) {
if (isSubsequence(nextStep, word)) {
res.add(word);
}
}
return res;
}
boolean isSubsequence(int[][] nextStep, String word) {
int indSoFar = 0; // start from beginning
char[] chars = word.toCharArray();
int strLen = nextStep.length - 1;
for (int i = 0; i < chars.length; i++) {
int curCharInd = nextStep[indSoFar][chars[i] - 'a'];
// 这里还是没搞懂为什么有没有等于都ok
// 补充:其实第一个条件可以去掉
// 虽然助教说这个是什么前一个,还有什么多开了一维,所有ok
// 我觉得其实是因为第二个条件已经囊括了第一个条件
if (indSoFar > strLen || curCharInd < indSoFar) {
return false;
}
indSoFar = curCharInd + 1;
}
return true;
}
private int[][] findNextStep(String str) {
int len = str.length();
// like a dp, we go from back to front
int[][] table = new int[len + 1][26];
// create one more space for init, -1, becasue nothing after last char
for (int j = 0; j < 26; j++) { // 其实只用初始化最后一行
table[len][j] = -1;
}
for (int i = len - 1; i >= 0; i--) {
for (int j = 0; j < 26; j++) {
char curChar = str.charAt(i);
int charInd = curChar - 'a';
table[i][j] = table[i + 1][j];
if (charInd == j) {
table[i][j] = i;
}
}
}
return table;
}
// 某同学写的自动机,明天再自己写
public List<String> findWords(String str, List<String> dict) {
// write your code here.
List<String> ans = new ArrayList<>();
if (str == null || str.length() == 0 || dict == null || dict.size() == 0) {
return ans;
}
int n = str.length();
int[][] nextChar = getNextChar(str);
for (String cur : dict) {
if (isValid(nextChar, cur)) {
ans.add(cur);
}
}
return ans;
}
boolean isValid(int[][] nextChar, String cur) {
int n = nextChar.length - 1;
int id = 0;
for (char a : cur.toCharArray()) {
if (id >= n || nextChar[id][a - 'a'] < id) {
return false;
}
id = nextChar[id][a - 'a'] + 1;
}
return true;
}
int[][] getNextChar(String str) {
int n = str.length();
int[][] nextChar = new int[n + 1][26];
for (int i = n; i >= 0; i --) {
for (int j = 0; j < 26; j ++) {
nextChar[i][j] = -1;
}
}
for (int i = n - 1; i >= 0; i --) {
int index = str.charAt(i) - 'a';
for (int j = 0; j < 26; j ++) {
nextChar[i][j] = nextChar[i + 1][j];
if (index == j) {
nextChar[i][j] = i;
}
}
}
return nextChar;
}
// 二分
public List<String> findWords(String str, List<String> dict) {
List<String> res = new ArrayList<>();
if (str == null || str.length() == 0 || dict == null || dict.isEmpty()) {
return res;
}
Map<Character, List<Integer>> charToLocation = new HashMap<>();
char[] chars = str.toCharArray();
for (int i = 0; i < chars.length; i++) {
List<Integer> tmp;
if (charToLocation.containsKey(chars[i])) {
tmp = charToLocation.get(chars[i]);
} else {
tmp = new ArrayList<Integer>();
}
tmp.add(i);
charToLocation.put(chars[i], tmp);
}
for (String word : dict) {
if (isSubsequence(word, charToLocation)) {
res.add(word);
}
}
return res;
}
private boolean isSubsequence(String word, Map<Character, List<Integer>> map) {
char[] chars = word.toCharArray();
int ind = -1;
for (int i = 0; i < chars.length; i++) {
char c = chars[i];
List<Integer> locs = map.get(c);
ind = binarySearchForFirstBiggerOrEqual(locs, ind);
if (ind == -1) {
return false;
}
}
return true;
}
private int binarySearchForFirstBiggerOrEqual(List<Integer> locs, int target) {
if (locs == null || locs.isEmpty()) {
return -1;
}
int start = 0;
int end = locs.size() - 1;
while (start + 1 < end) {
int mid = start + (end - start) / 2;
if (locs.get(mid) == target) {
start = mid;
} else if (locs.get(mid) < target) {
start = mid;
} else {
end = mid;
}
}
if (locs.get(start) > target) {
return locs.get(start);
}
if (locs.get(end) > target) {
return locs.get(end);
}
return -1;
}