演算法複雜度 o(1):
- 複雜最壞複雜度 是 o(s.length) 和 o(m*total)的最大值
碼程式碼速度要變快,變數,演算法要先想清楚
import java.util.*;
class Solution {
public List<Integer> findSubstring(String s, String[] words) {
m = words[0].length();
n = words.length;
cnt = new HashMap<>();
int total = 0;
for (String word : words) {
cnt.put(word, cnt.getOrDefault(word, 0) + 1);
total += word.length();
}
List<Integer> ans = new LinkedList<>();
// map[j]<str> 表示從[i,i+total -1]足要求的string的要求的出現各個位置
map = new HashMap[m];
int[] dp = new int[s.length()];
for (int i = 0; i < dp.length;i++) {
dp[i] = i + 1;
}
for (int i = 0; i < m; i++) {
if (i + total > s.length()) {
break;
}
boolean find = true;
map[i] = new HashMap<String, LinkedList<Integer>>();
for (int j = i + total - 1; j >= i + m - 1; j = j - m) {
String str = s.substring(j - m + 1, j + 1);
int num = cnt.getOrDefault(str, 0);
int occur = map[i].getOrDefault(str, new LinkedList<>()).size();
if (num > occur) {
// exist, 並且出現次數少
map[i].putIfAbsent(str, new LinkedList<>());
// 記錄開始位置
map[i].get(str).addFirst(j - m + 1);
dp[i + total - 1] = j - m + 1;
} else {
find = false;
break;
}
}
if (find) {
ans.add(i);
}
}
// 遍歷後面的
for (int j = m; j <= s.length() - total; j++) {
int tail = j + total - 1;
String str = s.substring(j - m + total, j + total);
if (cnt.getOrDefault(str, 0) == 0) {
// 當前字串不被包含;
dp[tail] = tail + 1;
continue;
}
// 上一個最遠的位置
int leftmost = dp[j + total - 1 - m];
// 上個滿足要求
while (!map[j % m].getOrDefault(str, new LinkedList<>()).isEmpty() && map[j % m].get(str).getFirst() < leftmost) {
map[j % m].get(str).pollFirst();
}
if (leftmost == j - m) {
// 當前位置的最遠, 預設能到達
int newMostleft = j;
if (!map[j % m].get(str).isEmpty()) {
// 肯定會到達這裡, 因為該str肯定會被前面包含
newMostleft = map[j % m].get(str).pollFirst();
}
map[j % m].get(str).add(tail - m + 1);
if (newMostleft == j - m) {
// 相同
dp[tail] = j;
ans.add(j);
} else {
// 不相同
dp[tail] = newMostleft + m;
}
} else {
int num = map[j % m].getOrDefault(str, new LinkedList<>()).size();
int all = cnt.get(str);
map[j % m].putIfAbsent(str, new LinkedList<>());
map[j % m].get(str).add(tail -m + 1);
if (num == all) {
int entry = map[j % m].get(str).getFirst();
// 順序
dp[tail] = entry + m;
map[j % m].get(str).pollFirst();
}
else {
// 更新為最
dp[tail] = leftmost;
if (tail - leftmost + 1 == total) {
ans.add(j);
}
}
}
}
return ans;
}
int n;
int m;
int k = 0;
Map<String, Integer> cnt;
Map<String, LinkedList<Integer>>[] map;
public static void main(String[] args) {
TreeSet<Integer> set;
Solution solution = new Solution();
List<Integer> ans = solution.findSubstring("aaa", new String[]{
"a", "a"
});
System.out.println(ans);
}
}
演算法2, trie樹匹配
import java.util.ArrayList;
import java.util.List;
class Solution {
public List<Integer> findSubstring(String s, String[] words) {
build(words);
int n = words.length;
this.words = words;
int cnt = 0;
for (String word : words) {
cnt += word.length();
}
List<Integer> ans = new ArrayList<>();
for (int i = 0; i <= s.length() - cnt; i++) {
find = false;
dfs(s, i, 0);
if (find) {
ans.add(i);
}
}
return ans;
}
public static void main(String[] args) {
Solution solution = new Solution();
List<Integer> ans = solution.findSubstring("wordgoodgoodgoodbestword", new String[]{
"word","good","best","good"
});
System.out.println(ans);
}
boolean find = false;
String[] words;
public void dfs(String s, int start, int depth) {
if (find) {
return;
}
if (depth == words.length) {
find = true;
return;
}
if (start == s.length()) {
return;
}
char ch = s.charAt(start);
int idx = ch - 'a';
if (root[idx] == null) {
return;
}
TrieNode node = null;
while (start < s.length()) {
node = node == null ? root[idx] : node.findChild(s.charAt(start));
start++;
if (node == null) {
return;
}
while (node.indexList.isEmpty() && start < s.length()) {
node = node.findChild(s.charAt(start++));
if (node == null) {
return;
}
}
if (node.indexList.isEmpty()) {
return;
}
int index = node.indexList.get(node.indexList.size() - 1);
node.indexList.remove(node.indexList.size() - 1);
dfs(s, start , depth + 1);
node.indexList.add(index);
if (start == s.length()) {
return;
}
}
}
class TrieNode {
TrieNode[] children = new TrieNode[26];
char ch;
int idx;
List<Integer> indexList;
public TrieNode(char ch) {
this.ch = ch;
children = new TrieNode[26];
this.idx = ch - 'a';
indexList = new ArrayList<>();
}
public TrieNode addChild(char ch) {
if (children[ch - 'a'] == null) {
children[ch - 'a'] = new TrieNode(ch);
}
return children[ch - 'a'];
}
public TrieNode findChild(char ch) {
return children[ch - 'a'];
}
public void terminal(int index) {
indexList.add(index);
}
public boolean hasTerminal() {
return indexList.isEmpty();
}
}
TrieNode[] root = new TrieNode[26];
public void build(String[] words) {
for (int i = 0; i < words.length; i++) {
buildTrie(words[i], i);
}
}
public void buildTrie(String word, int index) {
char ch = word.charAt(0);
int idx = ch - 'a';
if (root[idx] == null) {
root[idx] = new TrieNode(ch);
}
TrieNode curr = root[idx];
for (int i = 1; i < word.length(); i++) {
curr = curr.addChild(word.charAt(i));
}
curr.indexList.add(index);
}
}