題目連結:
題目意譯:
你被給定一個二元陣列 nums 以及一整數 k。
一次「k-位元翻轉」為從 nums 中選擇一個長度為 k 的子陣列並同時將子陣列中的 0 變成 1 、 1 變成 0。
回傳使陣列中變為沒有 0 存在最少所需的 k-位元翻轉次數。如果這不可能,則回傳 -1。
一個子陣列為一個陣列中一個連續部份。
限制:
1 ≦ nums.length ≦ 10 ^ 5
1 ≦ k ≦ nums.length
範例測資:
範例 1:
輸入: nums = [0,1,0], k = 1
輸出: 2
解釋: 翻轉 nums[0],然後翻轉 nums[2]。
範例 2:
輸入: nums = [1,1,0], k = 2
輸出: -1
解釋: 無論我們怎麼翻轉大小為 2 的子陣列,我們都無法讓陣列變成 [1,1,1]。
範例 3:
輸入: nums = [0,0,0,1,0,1,1,0], k = 3
輸出: 3
解釋:
翻轉 nums[0] 、 nums[1] 、 nums[2]:nums 變成 [1,1,1,1,0,1,1,0]
翻轉 nums[4] 、 nums[5] 、 nums[6]:nums 變成 [1,1,1,1,1,0,0,0]
翻轉 nums[5] 、 nums[6] 、 nums[7]:nums 變成 [1,1,1,1,1,1,1,1]
解題思維:
(令 n = nums.length)
首先,如果可以讓 nums 中的 0 全部變成 1,則必定存在一個解使得以任意位置 i 作為結尾的子陣列 [i - k + 1, i] 最多只會被翻轉恰好一次。而原因很單純,因為每翻轉兩次就會互消抵銷。
而我們可以看到 nums[0] 只有翻轉 [0, k - 1] 這個子陣列才能改變其數值。因此如果 nums[0] 是 0,則我們必須翻轉 [0, k - 1]。
而根據一開始的提及的性質,此時要改變 nums[1] 只會剩下翻轉 [1, k] 的選擇了(因為 [0, k - 1] 已經判斷過要不要翻了);剩下的一路同理,直到遇到 nums[n - k + 1] 這個位置。
可以看到 nums[n - k + 1] 後面(含自身)已經剩不到 k 個數字了,因此已經不存在其他的子陣列可以翻了([0, k - 1] ~ [n - k, n - 1] 在前面都判斷過了)。因此此時如果剩下的 nums[n - k + 1] ~ nums[n - 1] 有任何一者在經過前面的翻轉後依舊是 0,則不可能將 nums 全數變為 0。
接下來的問題就是要判斷當看到 nums[i] 時,前面的子陣列改變了 nums[i] 幾次。
而這個可以用前綴和(Prefix Sums,參見
這題)來處理。也就是說如果子陣列 [L, L + k - 1] 有被翻轉,則在索引值 L 上標記。
因此 nums[i] 被前面的子陣列改變的次數恰好是索引值 i - k + 1 ~ i - 1 有多少個標記。
此次分享到此為止,如有任何更加簡潔的想法或是有說明不清楚之地方,也煩請各位大大撥冗討論。