修改/替换/删除k次求最长相同子序列的问题
非常神奇的一个思路,适用于修改/替换/删除k次求最长相同子序列的问题。
这几道题都可以用这个思路:
424. 替换后的最长重复字符 - 力扣(LeetCode)
2831. 找出最长等值子数组 - 力扣(LeetCode)
1156. 单字符重复子串的最大长度 - 力扣(LeetCode)
2024. 考试的最大困扰度 - 力扣(LeetCode)
但是这个方法我觉得并不普及。
2831 找出最长等值子数组
class Solution {
public:int longestEqualSubarray(vector<int>& nums, int k) {int n = nums.size();int l = 0, max_cnt = 0, r = 0; // l: 左指针, max_cnt: 当前窗口内的最高频率unordered_map<int, int> hash; // 记录窗口 [l, r] 内每个元素的频率for (r = 0; r < n; ++r) {int cur = nums[r];// 1. 窗口扩张:将当前元素加入窗口,更新其频率hash[cur]++; // 2. 更新当前窗口内的最高频率// 注意:我们只关心当前加入的元素是否创造了新高,因为它可能成为新的目标值max_cnt = max(max_cnt, hash[cur]); // 3. 检查窗口有效性:核心判断// r - l + 1: 窗口长度// max_cnt: 窗口内最大频率// (r - l + 1 - max_cnt): 窗口内除了频率最高元素外的**其他元素**数量(即需要删除的元素数量)if (r - l + 1 - max_cnt > k) { // 如果需要删除的元素数量超过 k,窗口失效,必须收缩// 4. 窗口收缩:将左侧元素移出窗口hash[nums[l]]--; l++; // 左指针右移// *注意:这里不需要重新计算 max_cnt,因为左侧元素的移除,// 就算 max_cnt 变小了,窗口长度 r - l + 1 也变小了。// 只要当前窗口是合法的,我们总能保证 max_cnt 记录了最优解。}// 5. 循环结束,**max_cnt** 记录了当前所有有效窗口中的最大频率,即最长等值子数组的长度。}return max_cnt;}
};
我的直观感受就是非常神奇,看看gemini的解释:
424 替换后的最长重复字符
class Solution {
public:int characterReplacement(string s, int k) {int n = s.length();int l = 0, r = 0, maxCount = 0;vector<int> freq(26, 0);for (r = 0; r < n; ++r) {freq[s[r] - 'A']++;//只关心最大值,所以根本不用维护maxCount变量,只在出现更大值的时候更新maxCount = max(maxCount, freq[s[r] - 'A']);//只关心最大长度,窗口长度只增,不减少if (r - l + 1 - maxCount > k) {freq[s[l] - 'A']--;l++;}}return r - l;}
};
1156 单字符重复子串的最长长度
class Solution {
public:int maxRepOpt1(string text) {int n = text.length();vector<int> cnt(26, 0);vector<int> freq(26, 0);for (int i = 0; i < n; ++i)cnt[text[i] - 'a']++;int l = 0, maxCount = 0, r = 0, ans = 0;char maxChar;for (r = 0; r < n; ++r) {freq[text[r] - 'a']++;if (cnt[text[r] - 'a'] - 1 > maxCount)maxCount = freq[text[r] - 'a'];if (r - l + 1 - maxCount > 1) {freq[text[l] - 'a']--;l++;}// ans=max(ans,r-l+1);}return r - l;}
};
2024 考试的最大困扰度
class Solution {
public:int maxConsecutiveAnswers1(string answerKey, int k) {int n = answerKey.length();int l = 0, F_count = 0, ans = 0, T_count = 0;for (int r = 0; r < n; ++r) {char current_char = answerKey[r];if (current_char == 'F')F_count++;while (F_count > k) {if (answerKey[l] == 'F')F_count--;l++;}ans = max(ans, r - l + 1);}l = 0;for (int r = 0; r < n; ++r) {char current_char = answerKey[r];if (current_char == 'T')T_count++;while (T_count > k) {if (answerKey[l] == 'T')T_count--;l++;}ans = max(ans, r - l + 1);}return ans;}int maxConsecutiveAnswers(string answerKey, int k) {int n = answerKey.length();int max_count = 0, l = 0, r = 0;vector<int> freq(2, 0);for (int r = 0; r < n; ++r) {if (answerKey[r] == 'T') {freq[1]++;max_count = max(max_count, freq[1]);} else {freq[0]++;max_count = max(max_count, freq[0]);}if (r - l + 1 - max_count > k) {if (answerKey[l] == 'T')freq[1]--;elsefreq[0]--;l++;}}return min(max_count + k,n);}
};