演算法題:刪除 K 位數字

五道口宅男瀟澗發表於2015-05-21

1.問題描述

現有一個 n 位數,你需要刪除其中的 k 位,請問如何刪除才能使得剩下的數最大?

比如當數為 2319274, k=1 時,刪去 2 變成 319274 後是可能的最大值。

2.問題分析

[1]貪心解法

這題可以使用貪心策略,每次從高位向低位數,刪除高位比低位數字小的那位上的數字,直到刪除了k位之後,得到的數字肯定是最大值。

(1)刪數問題具有最優子結構:

(2)刪數問題具有貪心選擇性質:

設問題T已按照上面的方法刪除,假設 A=(y1,y2,···,yk) 是刪數問題的一個最優解。易知,若問題有解,則1≤k≤n。 (1)當k=1時,由前得證,A=(y1,A′)是問題的最優解,其中A′是A中不刪除了y1而刪除其他位的最優解; (2)當k=q時,由反證法,可得A=(y1,y2···,yq)是最優解; 當k=q+1時,由前得證,A=(y1,y2···,yq+yq+1)是最優解。 所以,刪數問題具有貪心選擇性質。

程式碼很容易實現,AC,1.484s,1.089MB

 

[2]動態規劃解法

根據上面的分析可以看出此題還可用動態規劃來解決,思路如下:

假設A(i,j)表示輸入數字(字串)的從第i位到第j位數字組成的字串,S(i,j)表示前i位中刪除j位得到的最優解,它實際上可以看做兩個子問題:如果刪除第j位,那麼S(i,j)等於前i-1位刪除j-1位的最優解加上第j位數字;如果不刪除第j位,那麼S(i,j)等於前i-1位刪除j位的最優解。於是便有下面的遞推式:

這個遞推式非常類似最長公共子序列問題的遞推式,所以解法也類似,在空間方面可以只使用一個一維陣列,加上一個額外的O(1)的空間,計算過程如下面製作的表格所示,除了第一列,其他中間元素都只依賴於上面一行對應位置S(i−1,j)和上面一行左邊位置S(i−1,j−1)兩個元素的大小,比較的是字串,使用字典序進行比較,C++內建的字串比較函式compare即可。

動態規劃實現程式碼 [這份程式碼沒有AC,只能得到60分就超時了,應該還可以改進]。

從這道題中可以看出,雖然動態規劃每次做出當前情況下最好的決策,但是為了做出最好的決策花費了大量的時間和空間,對於刪數問題貪心演算法應該是較好的解決方案。

打賞支援我寫出更多好文章,謝謝!

打賞作者

打賞支援我寫出更多好文章,謝謝!

演算法題:刪除 K 位數字

相關文章