前往
大廳
主題

LeetCode - 402. Remove K Digits 解題心得

Not In My Back Yard | 2022-09-24 12:00:05 | 巴幣 2 | 人氣 294

題目連結:


題目意譯:
給定代表著一個非負整數的字串 num 以及一整數 k,回傳從 num 中移除 k 個位數後最小可能得到的整數。

限制:
1 ≦ k ≦ num.length ≦ 10 ^ 5
num 只由數字組成。
num 沒有任何的前導零,除了零自身以外。



範例測資:
範例 1:
輸入: num = "1432219", k = 3
輸出: "1219"
解釋: 移除三個位數 4 、 3 和 2 來得到 1219,而這個數字是最小的。

範例 2:
輸入: num = "10200", k = 1
輸出: "200"
解釋: 移除開頭的 1 得到 200 這個數字。注意到輸出不應包含任何前導零。

範例 3:
輸入: num = "10", k = 2
輸出: "0"
解釋: 從數字中移除掉所有的位數,因為什麼都不剩所以數值為 0。


解題思維:
假設我們現在先不考慮 num 中有「0」出現的情況(因為有可能會產生前導零,會使討論複雜化)。可以看到每移除一個位數,必定會比原本的數字小,但是不一定是同位數長中最小的。例如 8872 可以移除一位數變成 872 和 887 等。 872 、 887 確實都小於 8872,但當中最小的是 872。

現在我們觀察以下例子:
(以下以藍色代表目前所在之位數、「X」代表尚未看到的位數)
當遇到 123475XXX…… 時,此時可以確定我們可以移除前面的「7」(如果尚有餘力的話,也就是 k > 0 時)。因為移除後比起 12347XXX……,12345XXX…… 一定比較小。

當遇到 45672XXX…… 時,跟上面類似,比起移除後得到 4567XXX……,4562XXX…… 是比較小的。同樣地,我們可以陸續推得
452XXX…… 比 456XXX…… 小、
42XXX…… 比 45XXX…… 小、
2XXX…… 比 4XXX…… 小。
所以在有餘力的情況下(即 k 夠大),最終我們會得到 2XXX…… 這個數字(如果 k 不夠大,則會停在上述推論中的某一步,例如 42XXX…… 等)。



因此,我們可以使用堆疊(Stack)像這題一般地來找到對「每一位數」來說前面哪些位數較小、哪些較大(忽略掉前面已經移除的)。只是本題中的堆疊需要是維護成非遞減的,因為這樣子堆疊頂端就會是前面所有位數的最大值。

然後在移除堆疊頂端的時候,即是代表我們要移除掉特定的某一位數,因此 k 也要跟著減去 1。而當 k 到達 0 時,我們便無法再從堆疊中移除任何元素,因此剩下的位數將保持原樣。



現在讓我們把「0」加回到討論當中。

從範例 2 可以看到,當我們得到的結果有前導零時,應自動消去。也就是可以視為移除前導零實際上不會花費任何一次「操作數」。

因此當我們的堆疊頂端是「0」的時候,就代表我們可以直接將其移除。因為這代表了我們有餘力把這個「0」前面所有位數移除掉,因而得到 0XXX…… 這樣子的數字。



最後,掃完每一位數後,如果 k 還大於 0 的話,則盡可能地把堆疊中的數字從頂端開始移除(因為頂端的數字比較大)。重複這個步驟直到堆疊為空或是 k = 0 為止。而剩下的數字即是所求最小的數字;若堆疊為空,則最小的數字為「0」本身。




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

創作回應

更多創作