1. 程式人生 > >#424 Longest repeating character replacement

#424 Longest repeating character replacement

我的問題:寫是寫出來了,但是用的方法是時間複雜度過高。

1. 先遍歷整個string,找出所有char的頻率。

2. initialize一個max值,作為儲存值和update max的標準。

3. 外loop:對於26個字母,每個都loop一遍。

4. 內loop:對於input string裡的每一個char,都loop一遍。對於當前的char,以當前為起點,根據k值和通過外loop選定的char來確定終結點,然後用start-end的string長度和max進行比較。如果比max大則更新。這樣內外結合的目的是嘗試以每個char開頭的所有可能性,用來避免以左邊為選定的當前char,再進行loop的暴力解決方案。

5. 這樣做的後果是,會出現time limit exceed. 因為有兩個大型loop,這道題的time complexity是O(n + 26*n^2) = O(n^2)。這道題的space complexity是O(26) = O(1)。節省空間的後果,就是以超長的時間奔跑作為代價。

6. 對sliding window這個操作極度不熟悉。對於一個cs學生來說真是慚愧。

美妙的答案:用了sliding window的做法,類似題目可見#3 -- Longest substring without repeating characters (https://leetcode.com/problems/longest-substring-without-repeating-characters/

)

1. 直接用一個大loop,把每個char都loop一遍。

2. 有一個start point和一個end point。start point是先固定,到特殊情況下再移動;end point就是用遍歷的方法,遍歷到input string中的每一個char。

3. start = 0, end = 0,從0來開始操作end point。然後在整個操作過程中,用一個有26個格子的array來記錄當前sliding window裡的各個字母的出現頻率。並且用一個叫做max的變數來儲存當前window下的最大頻率。(我們只需要在這裡記錄頻率,不需要記錄具體的字母,因為這道題只關心要改掉多少個char,並不關心是以哪個char為中心去改掉別的char。)

4. 如果每讀一個新的end point,就更新max,找到當前window裡的最大頻率。然後根據end - start + 1 - max來計算可以改掉的字元數量。如果end - start + 1 - max <= k,這就意味著還有空間,可以繼續移動end point。如果 > k,這就意味著沒有空間了,這個時候只能通過移動start point來調整sliding window。在這種情況下就要把start point上的這個char在當前頻率表裡的出現頻率 - 1,然後嘗試去繼續expand end point。

5. 在每次當前操作結束後,計算一下當前window裡的string長度,然後取這麼多長度裡的最大長度,return。

Time complexity: O(n)

Space complexity: O(26) = O(1) because we know that there are only 26 alphabet chars can be input.

Sliding window的本質:

1. start point and end point (two points)

2. a data structure to store the current string

3. From index 0, constantly move the ending point to the end of the string. Check the constrains every time we move the end point. If the constrain is violated, move the start point one index to the right, and delete that char from the data structure. 

4. Constantly check before each manipulation, try to get the largest (usually?) thing you want.

自己修正後並accepted的程式碼如下:

 

 1 class Solution {
 2     public int characterReplacement(String s, int k) {
 3         int[] frequency = new int[26];
 4         for(int i = 0; i < 26; i++){
 5             frequency[i] = 0;
 6         }
 7 
 8         int max = 0; // used to record the max length of substring
 9         int count = 0; // used to record the largest frequency in current window
10         int start = 0;
11         int end = 0;
12         
13         for (end = 0; end < s.length(); end++){
14             frequency[s.charAt(end) - 'A']++;
15             count = Math.max(count, frequency[s.charAt(end) - 'A']);
16             if(end - start + 1 - count > k){
17                 // delete start char in frequency array and move start point
18                 frequency[s.charAt(start) - 'A']--;
19                 start++;
20             }
21             max = Math.max(max, end - start + 1);
22         }
23 
24         return max;
25     }
26 }