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

题目

https://leetcode-cn.com/problems/longest-repeating-character-replacement/

思路

计算每个子串的字符总数,只要减去出现最多的字符的出现次数,剩下的就是需要替换的字符。只要出现替换的字符不超过k, 就不需要移动左指针 i 。

原版代码

/**
 * @param {string} s
 * @param {number} k
 * @return {number}
 */
var characterReplacement = function(s, k) {
	let result = 0;
	let max = 0;
	let cnt = new Array(26);
	cnt.fill(0,0,27);//记录每个字符在子串中出现的次数
	for (let i = 0, j = 0; j < s.length; j++) {
		let pos = s[j].charCodeAt() - 'A'.charCodeAt();
		cnt[pos]++;//对应字母出现次数+1
		max = Math.max(max, cnt[pos]);//实时更新最大

		//大于k的话就换不完了,移动直到满足条件
		while (j - i + 1 - max > k){
			max = 0;
            cnt[s[i++].charCodeAt() - 'A'.charCodeAt()]--;
            for (element of cnt){
                max = Math.max(max, element);
            }
		}
		result = Math.max(result, j - i + 1);	
	}
	return result;

};

优化代码

在原版的代码里面,很大一部分代码在 i 向右移动的时候去维护max的数值。这是因为在 i 向右移动的时候,很可能会造成max的减少,如果使用Math.max(max, s[s[i].charCodeAt - 'A'.charCodeAt]) ,是找不到新的max的。因为旧的max会遮盖掉新的max的减少。

但其实,维护max是不必要的。我们的result是通过 j - i + 1 算出来的,同时,我们达到最大的result的时候,这个子串应该是由max的字符 + k 个替换好的字符组成的。

即有:j - i + 1 = max + k 

k不变,所以我们找到最大的答案,其实找到max的最大值就可以了。

因此只需要在max变大的时候维护max就可以

/**
 * @param {string} s
 * @param {number} k
 * @return {number}
 */

var characterReplacement = function(s, k) {

	let result = 0;

	let cnt = new Array(26).fill(0);//cnt记录的永远都是【窗口里的字母】在【窗口中】出现的次数
	
	let max = 0;//用于统计窗口中某字母的最大重复次数

	//窗口只会不变(max不更新时)或者是增大(max更新时)
	for (let i = 0, j = 0; j < s.length; j++){
		let pos = s[j].charCodeAt() - 'A'.charCodeAt();
		cnt[pos]++;
		max = Math.max(max, cnt[pos]);

		//当j跑的太远超过了k+max的容量的时候,把i往右边挪动(窗口滑动)
		//这个时候为什么不更新max呢?因为是max把这个窗口撑到了这么大,就算max不再有过去那么大了,窗口的大小还在。
		//直到有了新的max,把窗口继续撑大
		if (j - i + 1 > k + max) {
			pos = s[i].charCodeAt() - 'A'.charCodeAt();
			cnt[pos]--;
			i++;
		}

		result = Math.max(result, j - i + 1);
	}
	return result;

};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值