1. 程式人生 > >從一串數字裡刪除k個數字,使得新的那串數字最小

從一串數字裡刪除k個數字,使得新的那串數字最小

        最近接觸一道有趣的演算法題,意思是:給定一串數字,這串數字有可能大於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);
}