题目
题目链接
解题思路
这是一个滑动窗口问题,需要:
- 找到包含所有五种宝石 (ABCDE) 的最短连续子串
- 考虑项链首尾相接的特性
- 剩余的宝石数量就是答案
解题步骤:
- 将字符串复制一遍处理首尾相接的情况
- 使用滑动窗口找到包含 ABCDE 的最短子串
- 如果找不到包含所有宝石的子串,返回 0
- 答案为原字符串长度减去最短子串长度
代码
#include <iostream>
#include <string>
#include <unordered_map>
using namespace std;int solve(string s) {int n = s.length();// 处理首尾相接s = s + s;// 记录需要的宝石unordered_map<char, int> need = {{'A', 1}, {'B', 1}, {'C', 1}, {'D', 1}, {'E', 1}};int needCount = 5; // 需要的不同宝石数// 滑动窗口unordered_map<char, int> window;int left = 0, right = 0;int valid = 0; // 已找到的不同宝石数int minLen = s.length() + 1; // 最短子串长度while(right < s.length()) {char c = s[right];right++;// 更新窗口数据if(need.count(c)) {window[c]++;if(window[c] == 1) valid++;}// 尝试缩小窗口while(valid == needCount) {minLen = min(minLen, right - left);char d = s[left];left++;if(need.count(d)) {window[d]--;if(window[d] == 0) valid--;}}}// 如果找不到包含所有宝石的子串if(minLen > n) return 0;// 返回剩余宝石数量return n - minLen;
}int main() {string s;while(cin >> s) {cout << solve(s) << endl;}return 0;
}
import java.util.*;public class Main {public static int solve(String s) {int n = s.length();// 处理首尾相接s = s + s;// 记录需要的宝石Map<Character, Integer> need = new HashMap<>();for(char c : "ABCDE".toCharArray()) {need.put(c, 1);}int needCount = 5;// 滑动窗口Map<Character, Integer> window = new HashMap<>();int left = 0, right = 0;int valid = 0;int minLen = s.length() + 1;while(right < s.length()) {char c = s.charAt(right);right++;// 更新窗口数据if(need.containsKey(c)) {window.put(c, window.getOrDefault(c, 0) + 1);if(window.get(c) == 1) valid++;}// 尝试缩小窗口while(valid == needCount) {minLen = Math.min(minLen, right - left);char d = s.charAt(left);left++;if(need.containsKey(d)) {window.put(d, window.get(d) - 1);if(window.get(d) == 0) valid--;}}}// 如果找不到包含所有宝石的子串if(minLen > n) return 0;// 返回剩余宝石数量return n - minLen;}public static void main(String[] args) {Scanner sc = new Scanner(System.in);while(sc.hasNext()) {String s = sc.next();System.out.println(solve(s));}}
}
def solve(s):n = len(s)# 处理首尾相接s = s + s# 记录需要的宝石need = {'A': 1, 'B': 1, 'C': 1, 'D': 1, 'E': 1}need_count = 5# 滑动窗口window = {}left = right = 0valid = 0min_len = len(s) + 1while right < len(s):c = s[right]right += 1# 更新窗口数据if c in need:window[c] = window.get(c, 0) + 1if window[c] == 1:valid += 1# 尝试缩小窗口while valid == need_count:min_len = min(min_len, right - left)d = s[left]left += 1if d in need:window[d] -= 1if window[d] == 0:valid -= 1# 如果找不到包含所有宝石的子串if min_len > n:return 0# 返回剩余宝石数量return n - min_lenif __name__ == "__main__":while True:try:s = input()print(solve(s))except:break
算法及复杂度
- 算法:滑动窗口
- 时间复杂度:\(\mathcal{O}(n)\),其中 \(n\) 为字符串长度
- 空间复杂度:\(\mathcal{O}(1)\),哈希表大小固定