Longest Repeating Character Replacement

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

这一题是一个sliding window的题目,但和别的大部分sliding window题目有点差别的是(起码最优解),别的sliding window都是在遍历的过程里,始终保持一个符合题目限定条件的window,然后在遍历这些有效windows的同时找到最优(或者最大)解。但这一题要做到这一点比较难。

这一题有效Window的定义其实是:

在同一个window里,字符串的长度减去出现最多的单个字符的数目要小于等于k。譬如说当K = 3的时候,你有一个abcdffesdaf,那么譬如abcd或者cdffe之类的都是符合条件的Window,因为abcd有四个字符,出现最多的单个字符的长度也只有1,那么你可以同时replace 4 - 1 = 3个使之成为一个有效的window,cdffe也类似,出现最多的单个字符是f,出现了两次,+3 = 5,也是有效的。如果你想一直维持一个有效的window,那么你必须在遍历的时候永远知道当前window里出现最多的字符是什么,出现最多的次数是多少。然后怎么在前后指针移动的时候永远用一个efficient的办法维持这两个信息。这其实挺难的,反正我自己没有想到哪个数据结构能够很有效的做到这一点。

所以这一题的最优解,是要维持出现过的当前最大的window size,即使这个window里面在之后的移动中可能变得并不符合规定。只要在符合规定并可以扩大window size的时候往前递增并继续追求最大解,那么在遍历的过程里最后肯定就能拿到最大的window size。这个问题最重要的是,如何最终window里面出现最多的单个字符的个数。这个在Window前进的时候很容易求得,但是在window缩小的时候,你就没法得知了。所以我们就采用一种类似贪心算法的策略,只要遍历的过程里我们可以不断提高这个最多的单个字符的个数,就可以了。因为只取大写英文字母,你可以用一个int[] chcounter = new int[26],然后window的右指针前进的时候chcounter[string.charAt(endPtr)]++,左指针前进的时候哦chcounter[string.charAt(startPtr)]--。Window只扩大不缩小。不停移动即可。

举个例子:

abcddefghijkklmnk,k = 3的情况

你最开始肯定可以得到一个有效的window size = 4 [abcd],然后在后指针前进的时候你会得到一个扩大的window [abcdd],因为这个时候你出现最多的字符是d,出现了两次。然后你的window size就扩大了。然后你维持着window的size为5不变,继续移动。你会发现你会开始移动到一些无效window,譬如[defgh]或者之后的[ghijk]这样的,没关系,这一题你求的只是最大值,而不是找出所有有效的window,你维持着这样大小的window继续移动,你就会走到[kklmn],然后继续右指针往前移动的时候,发现了一个更大的window [kklmnk],最后你就得到了这题的最优解6。

根据上面的解析,你可以得到下面的代码:

    public int characterReplacement(String s, int k) {
        int result = 0, longestSingleChar = 0, startPtr = 0;
        int[] charCount = new int[26];
        for (int i = 0; i < s.length(); i++) {
            char currentCh = s.charAt(i);
            charCount[currentCh - 'A']++;
            longestSingleChar = Math.max(longestSingleChar, charCount[currentCh - 'A']);
            if (i - startPtr + 1 - longestSingleChar > k) {
                charCount[s.charAt(startPtr) - 'A']--;
                startPtr++;
            }
            
            result = Math.max(i - startPtr + 1, result);
        }
        
        return result;
    }

reference: Loading...

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值