題目連結:
題目意譯:
你被給定一個索引值從 0 開始數的整數陣列 nums 以及一正整數 k。
你可以在陣列上執行任意次以下操作:
從陣列中選擇任意一個大小為 k 的子陣列,並將其中所有元素之值減去 1。
如果你可以將陣列中所有元素變為 0,則回傳真(True);反之,則回傳假(False)。
一個子陣列為一個陣列中一段連續非空的部份。
限制:
1 ≦ k ≦ nums.length ≦ 10 ^ 5
0 ≦ nums[i] ≦ 10 ^ 6
範例測資:
範例 1:
輸入: nums = [2,2,3,1,1,0], k = 3
輸出: true
解釋: 我們可以做以下操作:
- 選擇子陣列 [2,2,3]。結果陣列將會是 nums = [1,1,2,1,1,0]。
- 選擇子陣列 [2,1,1]。結果陣列將會是 nums = [1,1,1,0,0,0]。
- 選擇子陣列 [1,1,1]。結果陣列將會是 nums = [0,0,0,0,0,0]。
範例 2:
輸入: nums = [1,3,1,1], k = 2
輸出: false
解釋: 不可能使陣列中所有元素變為 0。
解題思維:
可以看到 nums[0] 只會被一個子陣列影響到,即 nums[0] ~ nums[k - 1]。因此 nums[0] 是多少,就要在該子陣列做多少次操作。
此時 nums[0] ~ nums[k - 1] 這個子陣列便不再需要任何操作了,不然 nums[0] 會降到低於 0 以下。因此此時換 nums[1] 只會被另一個子陣列影響到了,即 nums[1] ~ nums[k]。以此類推。
當然,這些子陣列會彼此重疊。並且很明顯地,如果直接對每一個子陣列直接掃過來得出最終的數值的話會很慢。
因此我們需要一個變數 C來紀錄當前已經實施過的操作數(一開始是 0),而移動到「下一個」數字的時候先行減去 C 來得到真正的數值。但這又會產生另一個問題,也就是如果只是單純每一個子陣列就將 C 增加的話,會有機會算到「過期」的操作。例如說,nums[0] ~ nums[k - 1] 和 nums[k] ~ nums[2k - 1] 這兩個子陣列沒有任何重疊,因此在前者做過的操作不能算到處理後者的時候。
而這要解決很簡單,根據子陣列的開頭索引值來標記當下操作數即可。例如說,nums[0] ~ nums[k - 1] 如果做了 x 次操作,則在另一個紀錄用的陣列索引值 0(或是乾脆直接使用 nums[0] 這個格子)紀錄下 x 這個數值。其他子陣列也是同理。
而「第一次過期」會發生於處理 nums[k] 時,此時只要將 C 減去處理 nums[0] 紀錄的 x 值即可;同理「第二次過期」時只要將 C 減去處理 nums[1] 的 x 值……以此類推。
整個過程期間如果發生 C > nums[i] 的情況,則代表要將前面的數字變為 0 勢必會將 nums[i] 降低到 0 以下。因此不可能讓 nums 中所有數字變成 0。
掃完之後,如果 C 不為 0(根據實作方式不同,可能要多處理一次「過期」的情況)的話代表 nums 最後 k - 1 個數字沒辦法剛好降到 0(也可以提前中斷然後掃剩下的數字,一樣記得處理「過期」)。
如果都沒有上述的問題,則代表我們可以將 nums 中所有數字降到 0。
此次分享到此為止,如有任何更加簡潔的想法或是有說明不清楚之地方,也煩請各位大大撥冗討論。