题目描述
给定两个字符串s1和s2和正整数K,其中s1长度为n1,s2长度为n2,在s2中选一个子串,满足:
- 该子串长度为n1+k
- 该子串中包含s1中全部字母,
- 该子串每个字母出现次数不小于s1中对应的字母,
我们称s2以长度k冗余覆盖s1,给定s1,s2,k,求最左侧的s2以长度k冗余覆盖s1的子串的首个元素的下标,如果没有返回-1。
输入描述
输入三行,第一行为s1,第二行为s2,第三行为k,s1和s2只包含小写字母
输出描述
最左侧的s2以长度k冗余覆盖s1的子串首个元素下标,如果没有返回-1。
用例
输入 | ab aabcd 1 |
输出 | 0 |
说明 | 无 |
解题思路分析
题目要求我们在s2
中找到一个长度为n1+k
的子串,使得该子串包含s1
的所有字符,并且每个字符在该子串中出现的次数不小于在s1
中的出现次数,返回该子串在s2
中的起始位置,如果没有找到这样的子串,返回-1
。
-
输入描述:
- 第一行:字符串
s1
。 - 第二行:字符串
s2
。 - 第三行:整数
k
。
- 第一行:字符串
-
输出描述:
- 返回
s2
中满足条件的子串首个元素下标,如果没有返回-1
。
- 返回
解题步骤:
-
字符计数:
- 使用两个哈希表分别记录
s1
中的字符频率和当前窗口中的字符频率。
- 使用两个哈希表分别记录
-
滑动窗口:
- 使用滑动窗口方法遍历
s2
,窗口大小为n1+k
。 - 初始化窗口的字符频率计数器,并与
s1
的字符频率计数器进行比较。
- 使用滑动窗口方法遍历
-
窗口更新:
- 每次移动窗口时,更新当前窗口的字符频率计数。
- 检查窗口内的子串是否满足条件,即每个字符的出现次数不小于
s1
中相应字符的次数。
-
返回结果:
- 找到满足条件的第一个窗口时,返回其起始索引。
- 如果遍历完所有窗口没有找到满足条件的子串,返回
-1
。
C++程序实现
#include <iostream>
#include <unordered_map>
#include <string>
using namespace std;
int find_substring(string s1, string s2, int k) {
int n1 = s1.size();
int n2 = s2.size();
if (n2 < n1 + k) {
return -1;
}
unordered_map<char, int> s1_count, window_count;
for (char c : s1) {
s1_count[c]++;
}
for (int i = 0; i < n1 + k; ++i) {
window_count[s2[i]]++;
}
auto matches = [&]() {
for (auto& p : s1_count) {
if (window_count[p.first] < p.second) {
return false;
}
}
return true;
};
if (matches()) {
return 0;
}
for (int i = n1 + k; i < n2; ++i) {
window_count[s2[i]]++;
window_count[s2[i - (n1 + k)]]--;
if (matches()) {
return i - (n1 + k) + 1;
}
}
return -1;
}
int main() {
string s1, s2;
int k;
cin >> s1 >> s2 >> k;
int result = find_substring(s1, s2, k);
cout << result << endl;
return 0;
}
python程序实现
def find_substring(s1, s2, k):
from collections import Counter
n1 = len(s1)
n2 = len(s2)
if n2 < n1 + k:
return -1
s1_count = Counter(s1)
window_count = Counter(s2[:n1 + k])
def matches():
for char, count in s1_count.items():
if window_count[char] < count:
return False
return True
if matches():
return 0
for i in range(n1 + k, n2):
window_count[s2[i]] += 1
window_count[s2[i - (n1 + k)]] -= 1
if matches():
return i - (n1 + k) + 1
return -1
# 输入
s1 = input().strip()
s2 = input().strip()
k = int(input().strip())
# 计算并输出结果
result = find_substring(s1, s2, k)
print(result)
解释
上述代码通过滑动窗口的方法在s2
中找到满足条件的子串,并返回其起始索引。C++和Python实现的逻辑是一致的,都通过计数器来维护当前窗口的字符频率,并与s1
的字符频率进行比较,以确定窗口是否满足条件。