• 作者: 负雪明烛
  • id: fuxuemingzhu
  • 公众号:每日算法题
  • 本文关键词:LeetCode,力扣,算法,算法题,字符串,双指针,刷题群

题目地址:https://leetcode.com/problems/longest-repeating-character-replacement/description/

题目描述

Given a string that consists of only uppercase English letters, you can replace any letter in the string with another letter at most k times. Find the length of a longest substring containing all repeating letters you can get after performing the above operations.

Note:
Both the string’s length and k will not exceed 104.

Example 1:

Input:
s = "ABAB", k = 2 Output:
4 Explanation:
Replace the two 'A's with two 'B's or vice versa. Example 2: Input:
s = "AABABBA", k = 1 Output:
4 Explanation:
Replace the one 'A' in the middle with 'B' and form "AABBBBA".
The substring "BBBB" has the longest repeating letters, which is 4.

题目大意

求一个字符串修改k个字符后,能够成的最长的相同字符组成的连续子序列。

解题方法

双指针

首先需要区分两个概念:子串(子数组)子序列。这两个名词经常在题目中出现,非常有必要加以区分。子串sub-string(子数组 sub-array)是连续的,而子序列 subsequence 可以不连续。

我读完今天这个题目之后,脑子里把题目转成了另外一个表达方式:求字符串中一个最长的区间,该区间内的出现次数较少的字符的个数不超过 k。

上面的表达方式跟题目是等价的,抽象成这种表达方式的好处是让我们知道这是一个区间题,求子区间经常使用的方法就是双指针

《挑战程序设计竞赛》这本书中把双指针叫做「虫取法」,我觉得非常生动形象。因为双指针移动的过程和虫子爬动的过程非常像:前脚不动,把后脚移动过来;后脚不动,把前脚向前移动

我分享一个双指针的模板,能解决大多数的双指针问题:

def findSubstring(s):
N = len(s) # 数组/字符串长度
left, right = 0, 0 # 双指针,表示当前遍历的区间[left, right],闭区间
counter = collections.Counter() # 用于统计 子数组/子区间 是否有效
res = 0 # 保存最大的满足题目要求的 子数组/子串 长度
while right < N: # 当右边的指针没有搜索到 数组/字符串 的结尾
counter[s[right]] += 1 # 增加当前右边指针的数字/字符的计数
while 区间[left, right]不符合题意:# 此时需要一直移动左指针,直至找到一个符合题意的区间
counter[s[left]] -= 1 # 移动左指针前需要从counter中减少left位置字符的计数
left += 1 # 真正的移动左指针,注意不能跟上面一行代码写反
# 到 while 结束时,我们找到了一个符合题意要求的 子数组/子串
res = max(res, right - left + 1) # 需要更新结果
right += 1 # 移动右指针,去探索新的区间
return res

简单介绍上面的模板,模板的思想是:以右指针作为驱动,拖着左指针向前走。右指针每次只移动一步,而左指针在内部 while 循环中每次可能移动多步。右指针是主动前移,探索未知的新区域;左指针是被迫移动,负责寻找满足题意的区间。

模板的整体思想是:

  1. 定义两个指针 leftright 分别指向区间的开头和结尾,注意是闭区间;定义 counter 用来统计该区间内的各个字符出现次数;
  2. 第一重 while 循环是为了判断 right 指针的位置是否超出了数组边界;当 right 每次到了新位置,需要增加 right 指针的计数;
  3. 第二重 while 循环是让 left 指针向右移动到 [left, right] 区间符合题意的位置;当 left 每次移动到了新位置,需要减少 left 指针的计数;
  4. 在第二重 while 循环之后,成功找到了一个符合题意的 [left, right] 区间,题目要求最大的区间长度,因此更新 resmax(res, 当前区间的长度)
  5. right 指针每次向右移动一步,开始探索新的区间。

模板中为什么不把 counter 放在 while 循环内部呢?因为如果放在 while 内部每次新建一个 counter 变量,统计区间的字符出现次数的时间复杂度是 O(N) ;放在 while 外部,每次增加 right 指向的字符的计数、减少 left 指向的字符的计数的是时间复杂度是 O(1) 。这也是常见的统计区间问题时的技巧。类似的,如果我们要求一个区间的的话,也可以用类似的思想去做。

代码

今天的代码可以直接套用上面的双指针模板,内层的 while 循环中的判断条件该区间内出现次数较少的字符的出现次数是否大于 k 。如果大于 k 的话,说明该区间不符合题意,需要移动 left 指针直至符合题意为止。

如果理解了上面的双指针模板之后,我做了动图帮助理解。

使用 Python2 写的代码如下。

class Solution(object):
def characterReplacement(self, s, k):
"""
:type s: str
:type k: int
:rtype: int
"""
N = len(s)
left, right = 0, 0 # [left, right] 都包含
counter = collections.Counter()
res = 0
while right < N:
counter[s[right]] += 1
while right - left + 1 - counter.most_common(1)[0][1] > k:
counter[s[left]] -= 1
left += 1
res = max(res, right - left + 1)
right += 1
return res

欢迎加入组织

算法每日一题是个互相帮助、互相监督的力扣打卡网站,其地址是 https://www.ojeveryday.com/

想加入千人刷题群的朋友,可以复制上面的链接到浏览器,然后在左侧点击“加入组织”,提交力扣个人主页,即可进入刷题群。期待你早日加入。

欢迎关注我的公众号:每日算法题

日期

2018 年 3 月 12 日
2021 年 2 月 2 日 —— 现在题解的这个动图是我做的第一个动图

【LeetCode】424. 替换后的最长重复字符 Longest Repeating Character Replacement(Python)的更多相关文章

  1. [Swift]LeetCode424. 替换后的最长重复字符 | Longest Repeating Character Replacement

    Given a string that consists of only uppercase English letters, you can replace any letter in the st ...

  2. Java实现 LeetCode 424 替换后的最长重复字符

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

  3. Leetcode 424.替换后的最长重复字符

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

  4. 【LeetCode】424. 替换后的最长重复字符

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

  5. 424 Longest Repeating Character Replacement 替换后的最长重复字符

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

  6. [LeetCode] Longest Repeating Character Replacement 最长重复字符置换

    Given a string that consists of only uppercase English letters, you can replace any letter in the st ...

  7. 【leetcode】424. Longest Repeating Character Replacement

    题目如下: Given a string that consists of only uppercase English letters, you can replace any letter in ...

  8. LeetCode 424. Longest Repeating Character Replacement

    原题链接在这里:https://leetcode.com/problems/longest-repeating-character-replacement/description/ 题目: Given ...

  9. Leetcode: Longest Repeating Character Replacement && G 面经

    Given a string that consists of only uppercase English letters, you can replace any letter in the st ...

随机推荐

  1. EXCEL-批量修改列宽

    WPS:先用鼠标选中一列,然后,长按ctrl键并且用鼠标选中剩余想要统一列宽的列,松开ctrl键,鼠标落在刚选中的任意一列的抬头上,鼠标右键,选择列宽,设置统一列宽即可.

  2. Excel-返回列表或数据库中的分类汇总(汇总可以实现要还是不要统计隐藏行功能) subtotal()

    SUBTOTAL函数 函数名称:SUBTOTAL 主要功能:返回列表或数据库中的分类汇总. 使用格式:SUBTOTAL(function_num, ref1, ref2, ...) 参数说明:Func ...

  3. SpringBoot集成Kafka的实战用法大全

    本文是SpringBoot+Kafka的实战讲解,如果对kafka的架构原理还不了解的读者,建议先看一下<大白话kafka架构原理>.<秒懂kafka HA(高可用)>两篇文章 ...

  4. 巩固javaweb第十五天

    巩固内容: 单选按钮: 在注册功能中,用户选择学历使用的是单选按钮,并且是多个单选按钮,每个选项对 应一个单选按钮,用户只能选择其中一个,这多个单选按钮的格式相同.如果用户要输入 的信息只有少数几种可 ...

  5. A Child's History of England.52

    'Arthur,' said the King, with his wicked eyes more on the stone floor than on his nephew, 'will you ...

  6. 大数据学习day39----数据仓库02------1. log4j 2. 父子maven工程(子spring项目的创建)3.项目开发(埋点日志预处理-json数据解析、清洗过滤、数据集成实现、uid回补)

    1. log4j(具体见log4j文档) log4j是一个java系统中用于输出日志信息的工具.log4j可以将日志定义成多种级别:ERROR  /  WARN  /  INFO  /  DEBUG ...

  7. vim一键整理代码命令

    vim下写代码超实用代码格式整理命令,仅需四步 ①先使用 gg 命令使光标回到第一行 ②shift+v 进入可视模式 ③shift+g 全选 ④按下  =  即可 混乱的代码格式 四步整理以后 工整又 ...

  8. 事务(@Transactional注解)的用法和实例

    参数 @Transactional可以配制那些参数及以其所代表的意义: 参数 意义 isolation 事务隔离级别 propagation 事务传播机制 readOnly 事务读写性 noRollb ...

  9. Spring Cloud Feign原理详解

    目录 1.什么是Feign? 2.Open Feign vs Spring Cloud Feign 2.1.OpenFeign 2.2.Spring Cloud Open Feign 3.Spring ...

  10. rust方法集

    随机数.数字对比.控制台输入 use std::io; use std::cmp::Ordering; use rand::Rng; fn main() { println!("please ...