我一直试图找到针对以下问题的O(n)解决方案:找到字符串b中字符串s的字符数(排列)的数量,其中s.length将始终小于b.length
我读到最佳解决方案涉及跟踪较小字符串中字符的频率,并在滑动窗口移动较大字符串时执行相同操作,但我不确定该实现的实际方式作品。现在我的解决方案不起作用(见评论),但即使这样做,也需要O(s + sn)时间。
编辑:示例输入:('aba', 'abaab')
。输出:3,因为'aba'
存在于b中,从索引0开始,'baa'
位于1,'aab'
位于2。
function anagramsInStr(s,b) {
//O(s)
let freq = s.split("").reduce((map, el) => {
map[el] = (map[el] + 1) || 1;
return map;
}, {});
let i = 0, j = s.length;
// O(n)
for (let char in b.split("")) {
// O(s)
if (b.length - char + 1 > s.length) {
let window = b.slice(i,j);
let windowFreq = window.split("").reduce((map, el) => {
map[el] = (map[el] + 1) || 1;
return map;
}, {});
// Somewhere about here compare the frequencies of chars found in the window to the frequencies hash defined in the outer scope.
i++;
j++;
}
}
}
答案 0 :(得分:1)
阅读评论,如果您有任何疑问,请与我们联系:
function countAnagramOccurrences(s, b) {
var matchCount = 0;
var sCounts = {}; // counts for the letters in s
var bCounts = {}; // counts for the letters in b
// construct sCounts
for (var i = 0; i < s.length; i++) {
sCounts[s[i]] = (sCounts[s[i]] || 0) + 1;
}
// all letters that occur in sCounts
var letters = Object.keys(sCounts);
// for each letter in b
for (var i = 0; i < b.length; i++) {
// maintain a sliding window
// if we already have s.length items in the counts, remove the oldest one
if (i >= s.length) {
bCounts[b[i-s.length]] -= 1;
}
// increment the count for the letter we're currently looking at
bCounts[b[i]] = (bCounts[b[i]] || 0) + 1;
// test for a match (b counts == s counts)
var match = true;
for (var j = 0; j < letters.length; j++) {
if (sCounts[letters[j]] !== bCounts[letters[j]]) {
match = false;
break;
}
}
if (match) {
matchCount += 1;
}
}
return matchCount;
}
console.log(countAnagramOccurrences('aba', 'abaab')); // 3
修改强>
关于运行时的说明:这是O(nk + m),其中 n 是 s 的长度, m 是 b 的长度, k 是 b 中唯一字符的数量。由于 m 总是小于 n ,我们可以减少到O(nk),因为 k 受固定常数(大小)的限制(字母表),我们可以进一步减少到O(n)。