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...