1.替换后的最长重复字符
示例如下:
下面我们来分析一下一个例子,其中K = 2
暴力枚举
这里的字符串s是仅由大写字母组成,首先我们尝试用暴力解法的思路来想一下这道题,通过从第一个字符开始进行枚举,如果出现了条件判断不成立,也就是说,需要替换的字符数量已经超过了K个,因此对于本次枚举的字符串再往后的字符就不可能是重复的字符串了,因此在从下一个字符进行枚举。
接下来继续从下一个字符开始枚举:
知道字符串s的末尾,然后在进行找最大重复子串的同时用一个变量记录最大长度即可,这就是暴力枚举。
滑动窗口
如果back走到上图的位置,那么此时已经无法满足替换K个窗口里的字符是该字符串是重复字符了,此时如果继续让back往后走,那么接下来的子串就不可能是重复字符的子串了,因此我们要移动prev:
然后此时窗口内的字符就满足重复字符的子串了,然后继续先后移动back
因此使用滑动窗口的关键是要进行判断:窗口中的子串是否可以不超过K次替换后是重复字符子串。
class Solution {
public:int characterReplacement(string s, int k) {//开辟一个数组,存储窗口中不同类字符出现的次数vector<int> v(26);int prev = 0,back = 0;int max_count = 0;int res = 0;while(back < s.length()){//进窗口v[s[back]-'A']++;//vector<int> v_copy(v);//std::sort(v_copy.begin(),v_copy.end(),std::greater<int>());//max_count = v_copy[0];max_count = *std::max_element(v.begin(),v.end());//判断while(back-prev+1-max_count > k){//出窗口v[s[prev]-'A']--;++prev;}//更新结果res = std::max(res,back-prev+1);++back;}return res;}
};
2.将字符串翻转到单调递增
示例:
动态规划
下面我们来分析一个示例:
通过上面例子的逐个位置分析可以理解到,最小翻转次数就是min(某个位置的前面的1的个数+位置后的0的个数),因此我们可以定义两个数组:dp1,dp0,分别表示某个位置前1的个数,位置后0的个数。
class Solution {
public:int minFlipsMonoIncr(string s) {//s中1的前缀和,0的后缀和vector<int> dp0(s.size());vector<int> dp1(dp0);int res = INT_MAX;for(int i = 1,j = s.size()-2;i<s.size();++i,--j){//1的前缀和if('1' == s[i-1])dp1[i] = dp1[i-1]+1;elsedp1[i] = dp1[i-1];//0的后缀和if('0' == s[j+1])dp0[j] = dp0[j+1]+1;elsedp0[j] = dp0[j+1];}for(int i = 0;i<dp0.size();++i)res = std::min(res,dp0[i]+dp1[i]);return INT_MAX == res ? 0 : res;}
};