记录一下刷题学到的新知识,不得不说实际写和阅读学习的收获是不一样的
题目:
给定两个字符串 s 和 p,找到 s中所有 p 的 异位词 的子串,返回这些子串的起始索引。不考虑答案输出的顺序。
异位词 指由相同字母重排列形成的字符串(包括相同的字符串)。
示例 1:
输入: s = "cbaebabacd", p = "abc"
输出: [0,6]
解释:
起始索引等于 0 的子串是 "cba", 它是 "abc" 的异位词。
起始索引等于 6 的子串是 "bac", 它是 "abc" 的异位词。
示例 2:
输入: s = "abab", p = "ab"
输出: [0,1,2]
解释:
起始索引等于 0 的子串是 "ab", 它是 "ab" 的异位词。
起始索引等于 1 的子串是 "ba", 它是 "ab" 的异位词。
起始索引等于 2 的子串是 "ab", 它是 "ab" 的异位词。
提示:
1 <= s.length, p.length <= 3 * 104s和p仅包含小写字母
题目刷多了之后我发现很多题都是在后面会有一些比较长的检查点,这时候对于性能优化就比较重要了,有些虽然可以在ide跑出来,但是可能力扣设置了超时时间会显示超过运行时间。
优化一般可以从算法和数据结构入手,比如前一篇文章就是把数据结构从数组改到哈希表(对象)从而提高性能;算法方面就是今天要提及的改进
思路: 1.一开始我的思路是先遍历大串,从每个位置截取和小串长度相同的子串,然后比较子串和小串的组成字母是否相同,相同则把序号i存入res
2.比较小串字母组成我是直接转成数组排序+join合成字符串。这种方法的特点就是简单容易想。代码如下:
var findAnagrams = function(s, p) {
let res = [];
s=[...s]
p=[...p]
let i = 0;let j=0
let len=p.length
let temp=""
while(i<s.length){
temp=s.slice(i,i+len).sort()
if(temp.join("")==p.sort().join("")){
res.push(i)
}
i++
}
return res
};
console.log(findAnagrams("cbaebabacd", "abc"));
但是这种方法的缺点就是比较计算量大,每次滑动窗口更新的时候都要进行一次排序。因此在后面的长字符串检测的时候挂了。
3.由于时间复杂度不算太高,数据结构我也想不出来有什么方法改进,所以就从检测字符串的算法来改进。要去比较每次取得的字符串和小串的字母组成是否相同,而且要更改尽量少(排序的开销比较大)。对于每次滑动窗口来说,对取得的子串只改动一个字母,所以是否可以存储每次的子串,并且可以单独修改某个字母。对于字母来说最多26个,可以维护一个map或者说对象的结构,键为字母,值为对象,维护结构时只要增减对应的字母的数量就可以。代码如下:
var findAnagrams = function(s, p) {
let res = [];
let sArr = Array.from(s);
let pArr = Array.from(p);
let len = p.length;
let pCounts = {};
let windowCounts = {};
for (let char of pArr) {
pCounts[char] = (pCounts[char] || 0) + 1;
}
for (let i = 0; i < len; i++) {
windowCounts[sArr[i]] = (windowCounts[sArr[i]] || 0) + 1;
}
for (let i = len; i < s.length; i++) {
// Check if the window has the same character counts as the pattern
if (compareObjects(windowCounts, pCounts)) {
res.push(i - len);
}
windowCounts[sArr[i]] = (windowCounts[sArr[i]] || 0) + 1;
windowCounts[sArr[i - len]]--;
if (windowCounts[sArr[i - len]] === 0) {
delete windowCounts[sArr[i - len]];
}
}
if (compareObjects(windowCounts, pCounts)) {
res.push(s.length - len);
}
return res;
};
//比较两个对象
function compareObjects(obj1, obj2) {
for (let key in obj1) {
if (obj1[key] !== obj2[key]) {
return false;
}
}
for (let key in obj2) {
if (obj2[key] !== obj1[key]) {
return false;
}
}
return true;
}
console.log(findAnagrams("cbaebabacd", "abc"));
比较数组需要单独进行循环,因为数组是引用对象,地址是不会相同的