从一串数字里删除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);
}

猜你喜欢

转载自blog.csdn.net/weixin_39400271/article/details/84590193