【LeetCode 438】找到字符串中所有字母异位词
题面:
思路:
哈希表+滑动窗口:也可用于 567
哈希表记录滑动窗口内字符个数,easy不详细赘述,俺代码可以继续优化,这里用了两个哈希表去做对比,可以优化成一个哈希表上的加减,当
h
a
s
h
[
c
]
=
=
0
hash[c]==0
hash[c]==0 时,说明当前字符
c
c
c 在字符串
p
p
p 和滑动窗口内出现的次数相同。
代码:
vector<int> findAnagrams(string s, string p) {
int n= (int)p.size();
vector<int> hashP(26);
vector<int> hash(26);
vector<int> res;
for(const auto& c : p) ++ hashP[c - 'a'];
for(int i = 0, j = 0; j < (int)s.size(); ++j) {
while(j - i + 1 > n) --hash[s[i++] - 'a'];
hash[s[j] - 'a'] ++;
if(j - i + 1 == n) {
bool flag = true;
for(size_t k = 0; k < 26; ++ k)
if(hash[k] != hashP[k]) {
flag = false;
break;
}
if(flag) res.push_back(i);
}
}
return res;
}
【LeetCode 567】字符串的排列
题面:
思路:
统计相同字符+滑动窗口:也可用于 438,微调一下就行
umm看了一下和官方题解差不多,就直接copy它的思路和代码了。
用
c
n
t
1
cnt1
cnt1 数组统计字符串
s
1
s1
s1 中各个字符的个数,
c
n
t
2
cnt2
cnt2 数组统计当前字串(滑动窗口内)各个字符的个数。
用变量
d
i
f
f
diff
diff 统计
c
n
t
1
cnt1
cnt1 和
c
n
t
2
cnt2
cnt2 内不同值的个数。若
d
i
f
f
=
=
0
diff==0
diff==0 则说明
c
n
t
1
=
=
c
n
t
2
cnt1 == cnt2
cnt1==cnt2,合法;否则说明
c
n
t
1
≠
c
n
t
2
cnt1 \ne cnt2
cnt1=cnt2,当前字串不是
s
1
s1
s1 的排列。
每次滑动窗口一进一出两个字符
x
x
x 和
y
y
y。
若
x
=
y
x=y
x=y,则
c
n
t
2
cnt2
cnt2 无变化;
若
x
≠
y
x\ne y
x=y,对于字符
x
x
x,若加入
x
x
x 之前有
c
n
t
1
[
x
]
=
c
n
t
2
[
x
]
cnt1[x]=cnt2[x]
cnt1[x]=cnt2[x],则说明加入
x
x
x 之后失衡,
d
i
f
f
+
1
diff+1
diff+1;若加入
x
x
x 之后有
c
n
t
1
[
x
]
=
c
n
t
2
[
x
]
cnt1[x]=cnt2[x]
cnt1[x]=cnt2[x],说明加入
x
x
x 之后
x
x
x 在字串和
s
1
s1
s1 中出现的次数相同,
d
i
f
f
−
1
diff-1
diff−1。
注意: 可用
c
n
t
[
x
]
=
c
n
t
2
[
x
]
−
c
n
t
1
[
x
]
cnt[x] = cnt2[x] - cnt1[x]
cnt[x]=cnt2[x]−cnt1[x] 以简化上述流程,将
c
n
t
1
[
x
]
cnt1[x]
cnt1[x] 与
c
n
t
2
[
x
]
cnt2[x]
cnt2[x] 的比较替换成
c
n
t
[
x
]
cnt[x]
cnt[x] 与
0
0
0 的比较。
代码:
bool checkInclusion(string s1, string s2) {
int n = (int)s1.size(), m = (int)s2.size();
if(n > m) return false;
vector<int> cnt(26);
int diff = 0;
for(int i = 0; i < n; ++i) {
-- cnt[s1[i] - 'a'];
++ cnt[s2[i] - 'a'];
}
for(int c : cnt)
if(c) ++ diff;
if(!diff) return true;
for(int i = n; i < m; ++i) {
int x = s2[i] - 'a', y = s2[i - n] - 'a';
if(x == y) continue;
if(!cnt[x]) ++ diff;
if(++ cnt[x] == 0) --diff;
if(!cnt[y]) ++ diff;
if(-- cnt[y] == 0) --diff;
if(!diff) return true;
}
return false;
}
俺原本的代码:
bool checkInclusion(string s1, string s2) {
if(s1.size() > s2.size()) return false;
int n = (int)s1.size();
unordered_map<int, int> mp;
for(const auto& c : s1) ++ mp[c - 'a'];
for(int i = 0, j = 0; j < (int)s2.size(); ++j) {
while(j - i + 1 > n) {
if(mp.find(s2[i] - 'a') != mp.end())
mp[s2[i] - 'a'] ++;
++i;
}
// 滑动窗口(字串)只统计在 s1 出现过的字符
// 若当前字符 s2[j] 没在 s1 出现过,则继续遍历(因为加入 s2[j] 对结果无贡献)
if(mp.find(s2[j] - 'a') != mp.end()) mp[s2[j] - 'a'] --;
else continue;
if(j - i + 1 == n) {
bool flag = true;
for(const auto& it : mp)
if(it.second != 0) {
flag = false;
break;
}
if(flag) return true;
}
}
return false;
}