漫画:删去k个数字后的最小值
轉載自??漫畫:刪去k個數字后的最小值
?
?
我們來舉一個栗子:
給定整數?541270936,要求刪去一個數,讓剩下的整數盡可能小。
此時,無論刪除哪一個數字,最后的結果都是從9位整數變成8位整數。既然同樣是8位整數,我們顯然應該優先把高位的數字降低,這樣對新整數的值影響最大。
?
如何把高位的數字降低呢?很簡單,我們把原整數的所有數字從左到右進行比較,如果發現某一位的數字大于它右面的數字,那么在刪除該數字后,必然會使得該數位的值降低,因為右面比它小的數字頂替了它的位置。
在咱們這個例子中,數字5右側的數字4小于5,所以刪除數字5,最高位數字降低成了4。
?
?
?
?
?
?
?
?
?
?
/*** 刪除整數的k個數字,獲得刪除后的最小值* @param num ?原整數* @param k ?刪除數量*/public static String removeKDigits(String num, int k) {String numNew = num;for(int i=0; i<k; i++){boolean hasCut = false;//從左向右遍歷,找到比自己右側數字大的數字并刪除for(int j=0; j<numNew.length()-1;j++){if(numNew.charAt(j) > numNew.charAt(j+1)){numNew = numNew.substring(0, j) + numNew.substring(j+1,numNew.length());hasCut = true;break;}}//如果沒有找到要刪除的數字,則刪除最后一個數字if(!hasCut){numNew = numNew.substring(0, numNew.length()-1);}//清除整數左側的數字0numNew = removeZero(numNew);}//如果整數的所有數字都被刪除了,直接返回0if(numNew.length() == 0){return "0";}return numNew;}private static String removeZero(String num){for(int i=0; i<num.length()-1; i++){if(num.charAt(0) != '0'){break;}num = num.substring(1, num.length()) ;}return num;}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));}小灰的代碼使用了兩層循環,外層循環基于刪除次數(k),內層循環從左到右遍歷所有數字。
當遍歷到需要刪除的數字時,利用字符串的自身方法subString() 把對應數字刪除,并重新拼接字符串。
顯然,這段代碼的時間復雜度是O(kn)。
?
結果,提交以后......
?
翻譯過來就是:恭喜你,打敗了16.56%的小伙伴!
?
?
1.每一次內層循環,都需要從頭遍歷所有數字
比如給定的整數是 11111111111114132,我們在第一輪循環中,需要遍歷大部分數字,一直遍歷到數字4,發現4>1,從而刪除4。
以目前的代碼邏輯,下一輪循環中,我們要從頭開始遍歷,再次重復遍歷大部分數字,一直遍歷到數字3,發現3>2,從而刪除3。
事實上,我們應該停留在上一次刪除的位置繼續進行比較。而不是從頭開始。
2.subString方法本身性能不高
subString方法的底層實現,涉及到了新字符串的創建,以及逐個字符的拷貝。這個方法自身的時間復雜度是O(n)。
因此,我們應該避免在每刪除以后數字后就調用subString方法。
?
?
?
/*** 刪除整數的k個數字,獲得刪除后的最小值* @param num ?原整數* @param k ?刪除數量*/public static String removeKDigits(String num, int k) {//新整數的最終長度 = 原整數長度 - kint newLength = num.length() - k;//創建一個棧,用于接收所有的數字char[] stack = new char[num.length()];int top = 0;for (int i = 0; i < num.length(); ++i) {//遍歷當前數字char c = num.charAt(i);//當棧頂數字大于遍歷到的當前數字,棧頂數字出棧(相當于刪除數字)while (top > 0 && stack[top-1] > c && k > 0) {top -= 1;k -= 1;}//遍歷到的當前數字入棧stack[top++] = c;}// 找到棧中第一個非零數字的位置,以此構建新的整數字符串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));}代碼中非常巧妙地運用了棧的特性,在遍歷原整數的數字時,讓所有數字一個個入棧,當某個數字需要刪除時,讓該數字出棧。最后,程序把棧中的元素轉化為字符串結果。
我們仍然以整數 541270936,k=3 為例:
遍歷到數字5,數字5入棧:
?
遍歷到數字4,發現棧頂5>4,棧頂5出棧,數字4入棧:
?
遍歷到數字1,發現棧頂4>1,棧頂4出棧,數字1入棧:
?
繼續遍歷數字2,數字7,依次入棧。
?
遍歷數字0,發現棧頂7>0,棧頂7出棧,數字0入棧:
?
此時k的次數已經用完,無需再比較,剩下的數字一口氣入棧:
?
此時棧中的元素就是最終的結果。
代碼只對所有數字遍歷了一趟,遍歷的時間復雜度是O(n),而后把棧轉化為字符串的時間復雜度也是O(n),所以最終的時間復雜度是O(n)。
同時,程序中利用棧來回溯遍歷過的數字以及刪除數字,所以程序的空間復雜度是O(n)。
?
?
?
?
leetcode原題鏈接如下,有興趣的小伙伴可以自己嘗試哦:
https://leetcode.com/problems/remove-k-digits/description/
總結
以上是生活随笔為你收集整理的漫画:删去k个数字后的最小值的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 中国限制稀土出口的措施有哪些
- 下一篇: Weebly Pro - Is an U