当前位置:   article > 正文

滑动窗口:给你一个仅由大写英文字母组成的字符串,你可以将任意位置上的字符替换成另外的字符,总共可最多替换 k 次。在执行上述操作后,找到包含重复字母的最长子串的长度。_给你一个仅由大写英文字母组成的字符串,你可以将任意位置上的字符替换成另外的字

给你一个仅由大写英文字母组成的字符串,你可以将任意位置上的字符替换成另外的字

一、问题描述

给你一个仅由大写英文字母组成的字符串,你可以将任意位置上的字符替换成另外的字符,总共可最多替换 k 次。在执行上述操作后,找到包含重复字母的最长子串的长度。

注意:
字符串长度 和 k 不会超过 104

示例 1:

  1. 输入:
  2. s = "ABAB", k = 2
  3. 输出:
  4. 4
  5. 解释:
  6. 用两个'A'替换为两个'B',反之亦然。


示例 2:

  1. 输入:
  2. s = "AABABBA", k = 1
  3. 输出:
  4. 4
  5. 解释:
  6. 将中间的一个'A'替换为'B',字符串变为 "AABBBBA"
  7. 子串 "BBBB" 有最长重复字母, 答案为 4

 题目来源:LeetCode   链接:https://leetcode-cn.com/problems/longest-repeating-character-replacement

二、解题思路

1.暴力法,一般时间都会超限

  1. class Solution {
  2. public:
  3. int characterReplacement(string s, int k) {
  4. int k2=k, maxlen=0, first=s.length();
  5. int i=0, j=0; //一个左边界i,一个右边界j
  6. while(i<s.length()&&j<s.length())
  7. {
  8. if(s[j]!=s[i])
  9. {
  10. if(k2>0)
  11. {
  12. k2--;
  13. first = first< j ? first: j; //first记录第一个跟s[i]不相同的元素下标
  14. //后面可以直接把i重新赋值为first,而不是i+1
  15. j++;
  16. }
  17. else //如果k次修改机会用完
  18. {
  19. int temp = j-i;
  20. maxlen = maxlen<temp?temp:maxlen; //记录最长字符串长度
  21. if((s.length()-first)>maxlen) //只有first后面的字符串大于目前的maxlen
  22. { //继续执行才有意义,否则直接break
  23. i = first; //把i赋值为first
  24. j = i+1; //j为i+1
  25. k2 = k; //k2复原为原值
  26. }
  27. else
  28. break;
  29. }
  30. }
  31. else
  32. {
  33. j++;
  34. }
  35. int temp = j-i;
  36. maxlen = maxlen<temp?temp:maxlen;
  37. }
  38. return maxlen;
  39. }
  40. };

2.滑动窗口法

  上面的暴力法最坏情况了的时间复杂度其实可以达到O(n2), 这是因为当k次修改机会用完又遇到跟左边界值s[i]不同的元素时,采取的策略是往回走,把i赋值为first,j赋值为i+1。而滑动窗口的思想就是一直往前滑,争取达到O(n)的时间复杂度。而这要怎么才能做到?

  该方法时记录滑动窗口内的最多个数的字符即charMax,只要满足right - left + 1 > charMax + k即可继续向右扩张,即right++,不满足的时候就窗口整体向右移动,即同时right++,left++。这时候,假设后面都没有更长的替换后连续字符串的话,那么这个窗口长度会一直不变,知道循环结束(right走到终点),而如果后面还有更长的替换后连续字符串的话,这个窗口就会再次扩张。最后返回窗口大小,就是所求的替换后最长连续字符串的长度。

  1. class Solution {
  2. public:
  3. int characterReplacement(string s, int k) {
  4. if(s.length()==0)
  5. return 0;
  6. int map[26]={0}; //map用来记录字符数
  7. int i=0, charmax=0; //map数组下标为键,内容为值
  8. for(int j=0;j<s.length();j++)
  9. {
  10. int index = s[j]-'A';
  11. map[index]++; //向右扩张一步
  12. charmax=charmax>map[index]?charmax:map[index]; //更新charmax
  13. if((j-i+1)>charmax+k)
  14. {
  15. map[s[i]-'A']--; //如果不符合条件,左边收缩
  16. //保持窗口长度不变
  17. i++;
  18. }
  19. }
  20. return s.length()-i;
  21. }
  22. };

三、总结

    1.滑动窗口通常由扩张、收缩、移动三种行为,根据解题过程的不同阶段采取不同的行为

    2.滑动窗口经常搭配map使用 ,意在记录滑动窗口中的信息

    3.滑动窗口很适合解决字符串类的题目

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/618931
推荐阅读
相关标签
  

闽ICP备14008679号