问题分析
在位数固定的前提下,让高位的数字尽量小,其值就较小。依据此贪婪策略就可以解决这个问题。
如何根据贪婪策略删除数字呢?总目标是删除高位较大的数字,具体地相邻两位比较,若高位比低位大则删除高位。
代码一般实现:
package com.demo.test.util;
/**
* @description: 给定一个整数,删除k个数后,使得剩余值最小
* @author: fengze
* @create: 2018-11-28 11:37
**/
public class TestRemoveBig {
public static String getOptimalValue(String value, int k) {
//校验输入值和删除个数关系
if (value.length() <= k) {
return "0";
}
//外层循环控制删除次数
for (int j = 0; j < k; j++) {
//内层循环控制比较次数
boolean flag = false;
for (int i = 0; i < value.length() - 1; i++) {
if (value.charAt(i) > value.charAt(i + 1)) {
value = value.substring(0, i) + value.substring(i + 1);
flag = true;
//每次循环删除一个数
break;
}
}
//未删除数时,将最后一个值删除
if (!flag) {
value = value.substring(0, value.length() - 1);
}
//移除前面为0的所有数值
removeZero(value);
}
if (value.length() == 0){
return "0";
}
return value;
}
private static void removeZero(String value) {
for (int i = 0; i < value.length(); i++) {
if (value.charAt(i) != '0')
break;
value = value.substring(1, value.length());
}
}
public static void main(String[] args) {
System.out.println(getOptimalValue("15397268",8));
}
}
效率分析:
1.每一次内层循环,都需要从头遍历所有数字
2.subString方法本身性能不高
subString方法的底层实现,涉及到了新字符串的创建,以及逐个字符的拷贝。这个方法自身的时间复杂度是O(n)。因此,我们应该避免在每删除以后数字后就调用subString方法。
高效率实现:
package com.demo.test.util;
/**
* @description: 给定一个整数,删除k个数后,使得剩余值最小(优化实现方案)
* @author: fengze
* @create: 2018-11-28 13:38
**/
public class TestRemoveBigOptimal {
public static String getOptimalValue(String value, int k) {
//校验输入值和删除个数关系
if (value.length() <= k) {
return "0";
}
//删除后剩余位数
int newLenth = value.length() - k;
//使用数组将剩余元素收集
char[] newValue = new char[newLenth];
//栈顶元素
int stackTop = 0;
//遍历元素,将符合要求的删除,不符合要求的放入数组中
for (int i = 0; i < value.length() ; i++) {
//判断数组最后放入元素是否比当前值大,大就更换;第一次不进入
while (stackTop > 0 && newValue[stackTop-1] > value.charAt(i) && k>0) {
stackTop--;
k--;
}
//更换符合要求数值
newValue[stackTop++] = value.charAt(i);
}
//找到数组中第一个非0数值
int zeroNum = 0;
while(zeroNum < newLenth && newValue[zeroNum] == '0'){
zeroNum++;
}
//返回结果
return zeroNum == newLenth ? "0" : new String(newValue,zeroNum,newLenth-zeroNum);
}
public static void main(String[] args) {
System.out.println(getOptimalValue("103970609",4));
}
}
代码中非常巧妙地运用了栈的特性,在遍历原整数的数字时,让所有数字一个个入栈,当某个数字需要删除时,让该数字出栈。最后,程序把栈中的元素转化为字符串结果。
代码只对所有数字遍历了一趟,遍历的时间复杂度是O(n),而后把栈转化为字符串的时间复杂度也是O(n),所以最终的时间复杂度是O(n)。
同时,程序中利用栈来回溯遍历过的数字以及删除数字,所以程序的空间复杂度是O(n)。