【算法問題】刪除k個數(shù)字后的最小值

刪除k個數(shù)字后的最小值

摘自漫畫算法:

題目:給出一個整數(shù)构诚,從該整數(shù)中去掉k個數(shù)字贵少,要求剩下的數(shù)字形成的新整數(shù)盡可能小,應該如何選取被去掉的數(shù)字滔灶?

其中整數(shù)的長度大于或等于k普碎,給出的整數(shù)大小可以超過long類型的數(shù)字范圍。什么意思录平?

例子:

假設給出一個整數(shù)1593212缀皱,刪去3個數(shù)字动猬,新整數(shù)最小的情況是1212啤斗。

圖1.png

假設給出一個整數(shù)30200,刪去1個數(shù)字赁咙,新整數(shù)最小的情況是200钮莲。

圖2.png

假設給出一個整數(shù)10彼水,刪去2個數(shù)字(注意,這里要求刪去的不是1個數(shù)字凤覆,而是2個),新整數(shù)的最小情況是0叛赚。

圖3.png

解題思路

這個題目要求我們刪去k個數(shù)字稽揭,但我們不妨把問題簡化一下:如果只刪除1個數(shù)字,如何讓新整數(shù)的值最邢啤?

我的第一感覺是優(yōu)先刪除最大的數(shù)字揪胃,但是不對。

注意:數(shù)字的大小固然重要随闪,數(shù)字的位置則更加重要骚勘。大家可以想一想铐伴,一個整數(shù)的最高位哪怕只減少1位俏讹,對數(shù)值的影響也是非常大的。

例子:

給出一個整數(shù)541270936泽疆,要求刪去1個數(shù)字,讓剩下的整數(shù)盡可能小殉疼。

此時捌年,無論刪除哪一個數(shù)字驱证,最后的結果都是從9位整數(shù)變成8位整數(shù)。既然同樣是8位整數(shù)抹锄,顯然應該優(yōu)先把高位的數(shù)字降低逆瑞,這樣對新整數(shù)的值影響最大。

解題思路 — 圖1.png

如何把高位的數(shù)字降低呢伙单?很簡單获高,把原整數(shù)的所有數(shù)字從左到右進行比較,如果發(fā)現(xiàn)某一位數(shù)字大于它右面的數(shù)字吻育,那么在刪除該數(shù)字后念秧,必然會使該數(shù)位的值降低布疼,因為右面比它小的數(shù)字頂替了它的位置。

在上面這個例子中游两,數(shù)字5右側的數(shù)字小于5,所以刪除數(shù)字5贱案,最高位數(shù)字降低成了4。

對于整數(shù)541270936侨糟,刪除一個數(shù)字所能得到的最小值是41270936瘩燥。那么對于41270936秕重,刪除一個數(shù)字的最小值是多少呢厉膀?

解題思路 — 圖2.png

接下來,從剛才的結果1270936中再刪除一個數(shù)字汰具,能得到的最小值又是多少呢菱魔?

由于1<2,2<7,7>0杰妓,所以被刪除的數(shù)字為7。

解題思路 — 圖3.png

這里的每一步都要求得到刪除一個數(shù)字后的最小值巷挥,經(jīng)歷3次验靡,相當于求出了刪除k(k=3)個數(shù)字后的最小值。

像這樣依次求得局部最優(yōu)解胜嗓,最終得到全局最優(yōu)解的思想,叫作貪心算法怔锌。

代碼實現(xiàn)

/**
 * 描述:刪除k個數(shù)字后的最小值問題变过。
 * <p>
 * Create By ZhangBiao
 * 2020/6/8
 */
public class RemoveKDigits {

    /**
     * 刪除整數(shù)的k個數(shù)字,獲取刪除后的最小值
     *
     * @param num 原整數(shù)
     * @param k   刪除數(shù)量
     * @return
     */
    public static String removeKDigits(String num, int k) {
        // 新整數(shù)的最終長度 = 原整數(shù)長度 - k
        int newLength = num.length() - k;
        // 創(chuàng)建一個棧媚狰,用于接收所有的數(shù)字
        char[] stack = new char[num.length()];
        int top = 0;
        for (int i = 0; i < num.length(); i++) {
            // 遍歷當前數(shù)字
            char c = num.charAt(i);
            // 當棧頂數(shù)字大于遍歷到的當前數(shù)字時,棧頂數(shù)字出棧(相當于刪除數(shù)字)
            while (top > 0 && stack[top - 1] > c && k > 0) {
                top -= 1;
                k -= 1;
            }
            // 遍歷到的當前數(shù)字入棧
            stack[top++] = c;
        }
        // 找到棧中第1個非零數(shù)字的位置楞件,依次構建新的字符串
        int offset = 0;
        while (offset < newLength && stack[offset] == '0') {
            offset++;
        }
        return offset == newLength ? "0" : new String(stack, offset, newLength - offset);
    }

    public static void main(String[] args) {
        System.out.println(removeKDigits("1593212", 3));
        System.out.println(removeKDigits("30200", 1));
        System.out.println(removeKDigits("10", 2));
        System.out.println(removeKDigits("541270936", 3));
    }

}

上述代碼非常巧妙地運用了棧的特性裳瘪,在遍歷原整數(shù)的數(shù)字時罪针,讓所有數(shù)字一個一個入棧,當某個數(shù)字需要刪除時泪酱,讓該數(shù)字出棧。最后墓阀,程序把棧中的元素轉化為字符串類型的結果。

下面仍然以整數(shù)541270936经伙,k=3為例:

  • 當遍歷到數(shù)字5時勿锅,數(shù)字5入棧帕膜。
代碼實現(xiàn) — 圖1.png
  • 當遍歷到數(shù)字4時垮刹,發(fā)現(xiàn)棧頂5>4达吞,棧頂5出棧荒典,數(shù)字4入棧。
代碼實現(xiàn) — 圖2.png
  • 當遍歷到數(shù)字1時契耿,發(fā)現(xiàn)棧頂4>1螃征,棧頂4出棧搪桂,數(shù)字1入棧盯滚。
代碼實現(xiàn) — 圖3.png
  • 然后繼續(xù)遍歷數(shù)字2、數(shù)字7内列,并依次入棧背率。
代碼實現(xiàn) — 圖4.png
  • 最后,遍歷數(shù)字0寝姿,發(fā)現(xiàn)棧頂7>0,棧頂7出棧饵筑,數(shù)字0入棧。
代碼實現(xiàn) — 圖5.png
  • 此時k的次數(shù)已經(jīng)用完架专,無序再次比較玄帕,讓剩下的數(shù)字一起入棧即可。
代碼實現(xiàn) — 圖6.png

此時棧中的元素就是最終的結果委刘。

上面的方法只對所有數(shù)字遍歷了一次,遍歷的時間復雜度是O(n)钱雷,把棧轉化為字符串的時間復雜度也是O(n),所以最終的時間復雜度是O(n)罩抗。

同時,程序中利用棧來回溯遍歷過的數(shù)字及刪除數(shù)字套蒂,所以程序的空間復雜度是O(n)。

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末烁挟,一起剝皮案震驚了整個濱河市骨坑,隨后出現(xiàn)的幾起案子撼嗓,更是在濱河造成了極大的恐慌,老刑警劉巖且警,帶你破解...
    沈念sama閱讀 217,406評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件礁遣,死亡現(xiàn)場離奇詭異,居然都是意外死亡祟霍,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評論 3 393
  • 文/潘曉璐 我一進店門醇王,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人厦画,你說我怎么就攤上這事滥朱。” “怎么了徙邻?”我有些...
    開封第一講書人閱讀 163,711評論 0 353
  • 文/不壞的土叔 我叫張陵畸裳,是天一觀的道長。 經(jīng)常有香客問我,道長颇象,這世上最難降的妖魔是什么并徘? 我笑而不...
    開封第一講書人閱讀 58,380評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮麦乞,結果婚禮上,老公的妹妹穿的比我還像新娘姐直。我一直安慰自己,他們只是感情好声畏,可當我...
    茶點故事閱讀 67,432評論 6 392
  • 文/花漫 我一把揭開白布插龄。 她就那樣靜靜地躺著能扒,像睡著了一般辫狼。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上膨处,一...
    開封第一講書人閱讀 51,301評論 1 301
  • 那天,我揣著相機與錄音鹃答,去河邊找鬼突硝。 笑死测摔,一個胖子當著我的面吹牛解恰,可吹牛的內容都是我干的。 我是一名探鬼主播护盈,決...
    沈念sama閱讀 40,145評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼紊服!你這毒婦竟也來了?” 一聲冷哼從身側響起欺嗤,我...
    開封第一講書人閱讀 39,008評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎煎饼,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體淤袜,經(jīng)...
    沈念sama閱讀 45,443評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡衰伯,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,649評論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了意鲸。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,795評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡读慎,死狀恐怖,靈堂內的尸體忽然破棺而出夭委,到底是詐尸還是另有隱情募强,我是刑警寧澤株灸,帶...
    沈念sama閱讀 35,501評論 5 345
  • 正文 年R本政府宣布擎值,位于F島的核電站,受9級特大地震影響鸠儿,放射性物質發(fā)生泄漏。R本人自食惡果不足惜汹粤,卻給世界環(huán)境...
    茶點故事閱讀 41,119評論 3 328
  • 文/蒙蒙 一品追、第九天 我趴在偏房一處隱蔽的房頂上張望玄括。 院中可真熱鬧肉瓦,春花似錦、人聲如沸泞莉。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,731評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽斯嚎。三九已至挨厚,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間疫剃,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,865評論 1 269
  • 我被黑心中介騙來泰國打工巢价, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人壤躲。 一個月前我還...
    沈念sama閱讀 47,899評論 2 370
  • 正文 我出身青樓碉克,卻偏偏與公主長得像凌唬,于是被迫代替她去往敵國和親漏麦。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,724評論 2 354