当前位置: 首页 > article >正文

LeetCode题练习与总结:替换后的最长重复字符--424

一、题目描述

给你一个字符串 s 和一个整数 k 。你可以选择字符串中的任一字符,并将其更改为任何其他大写英文字符。该操作最多可执行 k 次。

在执行上述操作后,返回 包含相同字母的最长子字符串的长度。

示例 1:

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

示例 2:

输入:s = "AABABBA", k = 1
输出:4
解释:
将中间的一个'A'替换为'B',字符串变为 "AABBBBA"。
子串 "BBBB" 有最长重复字母, 答案为 4。
可能存在其他的方法来得到同样的结果。

提示:

  • 1 <= s.length <= 10^5
  • s 仅由大写英文字母组成
  • 0 <= k <= s.length

二、解题思路

这个问题可以使用滑动窗口的技巧来解决。滑动窗口是一种常用的处理字符串或数组问题的方法,通过两个指针(通常称为left和right)来表示一个窗口,并随着算法的进行动态调整窗口的大小。

以下是解题步骤:

  1. 初始化两个指针left和right,都指向字符串的开始位置。
  2. 使用一个数组或者哈希表来记录当前窗口中每个字符的出现次数。
  3. 维护一个变量maxCount,记录当前窗口中出现次数最多的字符的出现次数。
  4. 移动right指针,扩大窗口,并更新字符出现次数和maxCount。
  5. 当窗口大小减去maxCount大于k时,说明无法通过替换k个字符来使得窗口内的所有字符相同,因此需要移动left指针,缩小窗口。
  6. 在每次移动right指针时,更新结果,即当前窗口的大小(right - left + 1)。
  7. 最终结果是所有窗口中最大的大小。

三、具体代码

class Solution {
    public int characterReplacement(String s, int k) {
        int left = 0, right = 0, maxCount = 0, result = 0;
        int[] count = new int[26]; // 因为字符串只包含大写字母,所以使用大小为26的数组记录每个字符的出现次数

        while (right < s.length()) {
            // 更新当前字符的出现次数
            count[s.charAt(right) - 'A']++;
            // 更新当前窗口中出现次数最多的字符的出现次数
            maxCount = Math.max(maxCount, count[s.charAt(right) - 'A']);
            // 如果当前窗口大小减去出现次数最多的字符的出现次数大于k,则移动left指针
            if (right - left + 1 - maxCount > k) {
                count[s.charAt(left) - 'A']--;
                left++;
            }
            // 更新结果
            result = Math.max(result, right - left + 1);
            // 移动right指针
            right++;
        }
        return result;
    }
}

四、时间复杂度和空间复杂度

1. 时间复杂度
  • 代码中有一个while循环,该循环会遍历字符串s中的每个字符一次。
  • 在while循环内部,对于每个字符,我们进行以下操作:
    • 更新字符出现次数的数组count,这是一个O(1)的操作,因为数组索引是常数时间访问的。
    • 更新maxCount,这是一个O(1)的操作,因为它只是比较两个整数值。
    • 检查是否需要移动left指针,这也是一个O(1)的操作。
    • 更新结果result,同样是O(1)的操作。
  • 因此,while循环的每次迭代都是O(1)的操作,而循环会执行n次,其中n是字符串s的长度。

综上所述,整个函数的时间复杂度是O(n),其中n是字符串s的长度。

2. 空间复杂度
  • 代码中使用了一个固定大小的数组count来记录每个字符的出现次数。由于字符串s只包含大写英文字母,所以数组的大小是26,这是一个常数。
  • 除了count数组外,代码中使用的其他变量(leftrightmaxCountresult)都是基本数据类型,它们占用固定大小的空间,不随输入字符串s的长度变化。

因此,整个函数的空间复杂度是O(1),表示它使用了常数级别的额外空间。

五、总结知识点

  1. 类定义class Solution 定义了一个名为 Solution 的类。

  2. 方法定义public int characterReplacement(String s, int k) 定义了一个公共方法 characterReplacement,它接受一个字符串 s 和一个整数 k 作为参数,并返回一个整数。

  3. 基本数据类型:代码中使用了 int 类型的变量,用于存储索引、计数、最大计数和结果。

  4. 数组int[] count = new int[26]; 创建了一个大小为26的整型数组,用于记录每个大写英文字母在当前窗口中的出现次数。

  5. ASCII码s.charAt(right) - 'A' 使用了字符的ASCII码值来进行数组索引的计算,这里将大写字母映射到数组索引。

  6. 循环while (right < s.length()) 使用了一个 while 循环来遍历字符串。

  7. 条件判断if (right - left + 1 - maxCount > k) 使用了条件判断来决定是否需要移动左指针。

  8. 数组元素访问和更新count[s.charAt(right) - 'A']++ 和 count[s.charAt(left) - 'A']-- 访问和更新数组中的元素。

  9. 最大值计算maxCount = Math.max(maxCount, count[s.charAt(right) - 'A']); 使用 Math.max 方法来计算两个值中的最大值。

  10. 滑动窗口技术:代码使用了滑动窗口技术来找到包含相同字母的最长子字符串的长度。滑动窗口通过两个指针 left 和 right 来维护当前窗口的边界。

  11. 算法逻辑:代码的逻辑体现了贪心算法的思想,即总是尝试将当前窗口扩展到最大,当窗口不满足条件时再收缩。

  12. 方法返回值return result; 表示方法的返回值,这里是计算得到的最长子字符串的长度。

以上就是解决这个问题的详细步骤,希望能够为各位提供启发和帮助。


http://www.kler.cn/a/411906.html

相关文章:

  • win10中使用ffmpeg和MediaMTX 推流rtsp视频
  • 鸿蒙心路旅程:从实践到创新——开发者的深度技术分享
  • Vue.Draggable使用nested-with-vmodel进行拖拽
  • logminer挖掘日志归档查找问题
  • 【漏洞复现】CVE-2020-13925
  • 第十六届蓝桥杯模拟赛第二期题解—Java
  • 使用 Jina Embeddings v2 在 Elasticsearch 中进行后期分块
  • React Native 应用程序测试指南
  • 网络安全:攻击和防御练习(全战课), DDos压力测试
  • shodan(7)
  • upload-labs-master第12关详细教程
  • 使用Go 语言连接并操作 MySQL 数据库
  • python+django5.1+docker实现CICD自动化部署springboot 项目前后端分离vue-element
  • Jackson、Gson、FastJSON三款JSON利器比拼
  • 用web前端写出一个高校官网
  • iOS 19 重大更新泄露,将带来更“聪明”的 Siri 挑战 ChatGPT
  • sqlite3自动删除数据的两种设置方式记录
  • 【单点知识】基于PyTorch进行模型部署
  • Java基础夯实——2.7 线程上下文切换
  • IDEA实现Oracle连接以及基本的增删改查操作步骤详解
  • 网易游戏用户流失预测实践
  • 【公益接口】不定时新增接口,仅供学习
  • 高校宿舍节能用电现状及智慧监管平台构建
  • javax.xml.ws.soap.SOAPFaultException: ZONE_OFFSET
  • 鸢尾花Iris训练数据和测试数据的分割和训练数据的散点图矩阵绘制
  • Linux中的“块”是什么