前往
大廳
主題

LeetCode - 1888. Minimum Number of Flips to Make the Binary String Alternating 解題心得

Not In My Back Yard | 2021-09-22 00:00:05 | 巴幣 0 | 人氣 210

題目連結:


題目意譯:
你被給定一個二元字串 s。你被允許以任意序列在字串上執行兩種操作:
類型-1:移除字串 s 開頭字元並將其放到字串結尾。
類型-2:挑 s 中的任一字元並翻轉其值,即如果其值為 '0' 則變為 '1',反之亦然。

回傳你將 s 變為交錯所需的最少類型-2 操作數。

一字串稱為交錯的如果任兩個相鄰字元皆相異。

例如,字串 "010" 和 "1010" 為交錯的,而字串 "0100" 則不是。

限制:
1 ≦ s.length ≦ 10 ^ 5
s[i] 只會是 '0' 或是 '1' 。



範例測資:
範例 1:
輸入: s = "111000"
輸出: 2
解釋: 使用第一個操作兩次使得 s = "100011"。
然後使用第二個操作於第三和第六個元素使得 s = "101010"。

範例 2:
輸入: s = "010"
輸出: 0
解釋: 字串已經是交錯的了。

範例 3:
輸入: s = "1110"
輸出: 1
解釋: 在第二個元素上使用第二個操作使得 s = "1010"。


解題思維:
本題可以使用滑動視窗(Sliding Window)的想法來求得所求。

基本上就是我們將 s 串接到 s 自身,例如 s = "1110" 將會變成 s = "11101110"。

因此這樣我們窮舉出新字串的所有與原字串長度相同的子字串時,即等價於我們正在套用第一種操作。所以上面的 s = "11101110",會依序得子字串 "1110" 、 "1101" 、 "1011" 、"0111" 和 "1110"(又回到了起點)。

因此如果此時我們將所有子字串與兩種交錯字串(0 開頭和 1 開頭)去比對不同之處,即可得到該子字串所需第二種操作(看哪個開頭所得到的差別最小,即是該子字串的最小操作數)。

所以,以 s = "11101110" 為例,我們就像是在進行以下動作:
11101110
1010
0101
與 1 開頭差別:1
與 0 開頭差別:3
該子字串最少操作數:1

11101110
1010
0101
與 1 開頭差別:3
與 0 開頭差別:1
該子字串最少操作數:1

11101110
  1010
  0101
與 1 開頭差別:1
與 0 開頭差別:3
該子字串最少操作數:1

11101110
   1010
   0101
與 1 開頭差別:3
與 0 開頭差別:1
該子字串最少操作數:1

可以看到在所有子字串中最少的操作數為 1(此例中剛好所有子字串最少操作數皆相等),所以 s = "1110" 時的答案為 1 。而其他測資也是同理。

等等,那滑動視窗要套用在哪呢?可以看到上面的呈現方式剛好符合滑動視窗的意涵,因為例如
11101110
  1010
  0101
的子字串,到
11101110
   1010
   0101
的子字串分別與 1 開頭、0 開頭去比對不需要每到下一個子字串就要從頭比起。可以看到兩者之間只有藍色(新增之字元)與紅色(消失之字元)之差別,所以只要特別判斷這兩個位置的字元便可以從原本的子字串與交錯字串的差別字元數,去得到「下一個」與交錯字串的差別字元數。

這樣一來便可以節省不少時間,而實際上時間複雜度從原本的 O(n ^ 2) 直接降低成了 O(n) ,其中 n = s.length 。




此次分享到此為止,如有任何更加簡潔的想法或是有說明不清楚之地方,也煩請各位大大撥冗討論。

創作回應

更多創作