LeetCode 424. 替换后的最长重复字符(中等)

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

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

注意:字符串长度 和 不会超过 10^4。

 

示例 1:

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

示例 2:

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

我的Java代码:

思路:用两个指针,第一个指针用来遍历整个字符串,第一个指针指向的字母称为靶字母,第二个指针从靶字母开始向后遍历,并对遇到的与靶字母不同的字母进行计数。当遇到的不同的字母多与可修改数时,以该靶字母为首的子串结束计数,两个指针之间的差值就是该子串的长度。考虑到字符串尾部又连续字母的情况,因此当第二个指针走到字符串尾部但是遇到的不同字母数仍小于可修改数时,就将靶字母前面的字母也修改掉。遍历整个字符串,取所有子串的最大值。这种方法效率很低。

class Solution {
    public int characterReplacement(String s, int k) {
		char[] letters = s.toCharArray();
		int max = 0;
		for(int i = 0;i < letters.length-k;i++) {
			char letter = letters[i]; //靶字母
			int num = 0; //保存的是中间不同于靶字母的字母
			int j = 0; //最长连续字母的长度
			
			//不同于靶字母的字母超过修改数后结束
			while(num <= k) {
				j++;
				if(i+j >= letters.length) {
					break;
				}
				if(letters[i+j] != letter) {
					num++;
				}
			}
			
			if(num <= k) {
				j += k-num;
			}
			if(j > letters.length) {
				j = letters.length;
			}
			if(j > max) {
				max = j;
			}
		}
		return max;
    }
}

学习别人的代码:

作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/longest-repeating-character-replacement/solution/ti-huan-hou-de-zui-chang-zhong-fu-zi-fu-n6aza/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

思路:双指针

我们可以枚举字符串中的每一个位置作为右端点,然后找到其最远的左端点的位置,满足该区间内除了出现次数最多的那一类字符之外,剩余的字符(即非最长重复字符)数量不超过 k 个。

这样我们可以想到使用双指针维护这些区间,每次右指针右移,如果区间仍然满足条件,那么左指针不移动,否则左指针至多右移一格,保证区间长度不减小。

虽然这样的操作会导致部分区间不符合条件,即该区间内非最长重复字符超过了 k 个。但是这样的区间也同样不可能对答案产生贡献。当我们右指针移动到尽头,左右指针对应的区间的长度必然对应一个长度最大的符合条件的区间。

实际代码中,由于字符串中仅包含大写字母,我们可以使用一个长度为 26 的数组维护每一个字符的出现次数。每次区间右移,我们更新右移位置的字符出现的次数,然后尝试用它更新重复字符出现次数的历史最大值,最后我们使用该最大值计算出区间内非最长重复字符的数量,以此判断左指针是否需要右移即可。

一些理解:

  • maxn代表曾经区间中出现过最多次的字符次数,这时的区间最长,因此实际上是保存了最大的区间长度。
  • 26位int数组是维护当前区间中的字符出现次数。
class Solution {
    public int characterReplacement(String s, int k) {
        int[] num = new int[26];
        int n = s.length();
        int maxn = 0;
        int left = 0, right = 0;
        while (right < n) {
            num[s.charAt(right) - 'A']++;
            maxn = Math.max(maxn, num[s.charAt(right) - 'A']);
            if (right - left + 1 - maxn > k) {
                num[s.charAt(left) - 'A']--;
                left++;
            }
            right++;
        }
        return right - left;
    }
}

作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/longest-repeating-character-replacement/solution/ti-huan-hou-de-zui-chang-zhong-fu-zi-fu-n6aza/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值