從一串數字裡刪除k個數字,使得新的那串數字最小
阿新 • • 發佈:2018-12-06
最近接觸一道有趣的演算法題,意思是:給定一串數字,這串數字有可能大於long的最長長度,譬如12542670021,從這串數字中刪除k個數字,使得新數字串在所有可能性結果中最小,那麼應該刪除哪k個數字呢?
下面給出思路和程式碼,以及程式碼的優化。
當然,數字的大小高位影響最大,所以首先考慮的是最高為,即從最左邊開始。
1 | 2 | 5 | 4 | 2 | 6 | 7 | 0 | 0 | 2 | 1 |
如果這裡k=1,顯然刪除數字5,會得到最小值,即
1 | 2 | 4 | 2 | 6 | 7 | 0 | 0 | 2 | 1 |
如果再繼續刪除一個呢?將會是刪除數字4,即
1 | 2 | 2 | 6 | 7 | 0 | 0 | 2 | 1 |
從上面結果來看,邏輯思路是從左到右遍歷判斷左邊的是否大於右邊的,如果大於,則刪掉,否則,就儲存。
當刪除第三個數字時,就會判斷1<2,儲存;2=2,儲存;2<6,儲存;6<7,儲存;7>0,刪除7,即
1 | 2 | 3 | 6 | 0 | 0 | 2 | 1 |
程式碼如下:
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(); 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); } //清除最前面的0 numNew = removeZero(numNew); } //如果整數所有數字都被刪除,則直接返回0 if(numNew.length()==0){ return "0"; } return numNew; } private static String removeZero(String numNew) { for(int i=0; i<numNew.length(); i++){ if(numNew.charAt(i)!='0'){ break; } numNew = numNew.substring(1, numNew.length()); } return numNew; }
對於上面程式碼,實現是可以實現,但是時間複雜度為O(kn),效能太差,下面對程式碼進行優化:
public static String removeKDigits2(String num, int k){
//新整數長度
int 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);
//當棧頂的值大於正在遍歷的數字,就出棧。即top--,將當前遍歷的值給到棧頂位置
while(top>0 && stack[top-1]>c && k>0){
top -= 1;
k -= 1;
}
stack[top] = c;
top++;
}
int offset = 0;
while(offset < newLength && stack[offset]=='0'){
offset++;
}
return offset==newLength?"0":new String(stack, offset, newLength-offset);
}