代码写的很乱。参考的思路和昨天的Minimum Window Substring有类似。参考的文章是:http://discuss.leetcode.com/questions/210/substring-with-concatenation-of-all-words
代码里还特意把字符串转成数字id用来简化,这个优化不是必须的,没有的话代码会简单点。
一开始是用字典计数,然后穷举。后来时间不过,就只能用Min Window类似的双指针扫描的思路优化,保证一遍下来。差不多是O(n)的复杂度。
又看了一下我和参考中代码的区别,由于受到昨天的影响,我还在计算每个字符(串)超出的情况,其实现在只要记录全部的字符串数n就行了,维持一个窗口,因为肯定是连续的,这样代码可以简化许多。
我的代码:
import java.util.ArrayList; import java.util.HashMap; public class Solution { public ArrayList<Integer> findSubstring(String S, String[] L) { // Start typing your Java solution below // DO NOT write main() function ArrayList<Integer> ret = new ArrayList<Integer>(); if (L.length == 0) return ret; HashMap<String, Integer> ids = new HashMap<String, Integer>(); HashMap<Integer, Integer> neededCount = new HashMap<Integer, Integer>(); int len = L[0].length(); int[] LL = new int[S.length() - len + 1]; // convert S to LL for (int i = 0; i+len <= S.length(); i++) { String s = S.substring(i, i+len); if (!ids.containsKey(s)) { int id = ids.size() + 1; ids.put(s, id); } int id = ids.get(s); LL[i] = id; } // init neededCount for (int i = 0; i < L.length; i++) { if (!ids.containsKey(L[i])) { return ret; } int id = ids.get(L[i]); if (neededCount.containsKey(id)) { int c = neededCount.get(id); neededCount.put(id, c+1); } else { neededCount.put(id, 1); } } HashMap<Integer, Integer> currentCount = new HashMap<Integer, Integer>(); for (int i = 0; i < len; i++) { currentCount.clear(); int total = 0; int left = i; int right = left; while (right < LL.length) { int id = LL[right]; if (!neededCount.containsKey(id)) { right += len; left = right; currentCount.clear(); total = 0; continue; } if (!currentCount.containsKey(id)) { currentCount.put(id, 1); } else { int c = currentCount.get(id); if (c >= neededCount.get(id)) { // == // move left forward while (left <= right) { if (LL[left] == id) { currentCount.put(id, c-1); total--; left += len; break; } left += len; } if (left > right) { right += len; left = right; currentCount.clear(); total = 0; continue; } } c = currentCount.get(id); currentCount.put(id, c+1); } total++; if (total == L.length) { ret.add(left); // move left forward int l = LL[left]; int c = currentCount.get(l); currentCount.put(l, c-1); total--; left += len; } right+=len; } } return ret; } }
参考代码:
class Solution { public: vector<int> findSubstring(string S, vector<string> &L) { // Start typing your C/C++ solution below // DO NOT write int main() function int m = S.size(), n = L.size(), len = L[0].size(); map<string, int> ids; vector<int> need(n, 0); for (int i = 0; i < n; ++i) { if (!ids.count(L[i])) ids[L[i]] = i; need[ids[L[i]]]++; } vector<int> s(m, -1); for (int i = 0; i < m - len + 1; ++i) { string key = S.substr(i, len); s[i] = ids.count(key) ? ids[key] : -1; } vector<int> ret; for (int offset = 0; offset < len; ++offset) { vector<int> found(n, 0); int count = 0, begin = offset; for (int i = offset; i < m - len + 1; i += len) { if (s[i] < 0) { // recount begin = i + len; count = 0; found.clear(); found.resize(n, 0); } else { int id = s[i]; found[id]++; if (need[id] && found[id] <= need[id]) count++; if (count == n) ret.push_back(begin); // move current window if ((i - begin) / len + 1 == n) { id = s[begin]; if (need[id] && found[id] == need[id]) count--; found[id]--; begin += len; } } } } return ret; } };