贪婪策略:数字去掉几位求最小值实现

问题分析

在位数固定的前提下,让高位的数字尽量小,其值就较小。依据此贪婪策略就可以解决这个问题。

如何根据贪婪策略删除数字呢?总目标是删除高位较大的数字,具体地相邻两位比较,若高位比低位大则删除高位。

代码一般实现:

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)

猜你喜欢

转载自blog.csdn.net/fz13768884254/article/details/84583831