最少步数归零问题 | 豆包MarsCode AI刷题

159 阅读5分钟

问题描述

小R拿到了一个长度为n的数组,其中每个元素都是一个正整数。小R发现每次可以删除某个数组中某个数的一位数字,这样可以逐步将所有数字变为0。他想知道,要将数组中所有数字都变为0,最少需要多少步?

例如:对于数字 103,小R可以选择删除第1位数字,将其变为 3;或者删除第2位数字,变为 13,又或者删除第3位数字,将其变为 10。最终目标是将所有数字都删除为0。


测试样例

样例1:

输入:n = 5,a = [10, 13, 22, 100, 30]
输出:7

样例2:

输入:n = 3,a = [5, 50, 505]
输出:4

样例3:

输入:n = 4,a = [1000, 1, 10, 100]
输出:4

二、问题本质

从本质上来看,这属于一个组合优化类型的问题。在数组中的每一个正整数,其每一位数字都存在被删除的可能性,这些不同的删除选择相互组合、相互影响,共同决定了最终将所有数字变为 0 所需要的总操作步数。

随着数组中元素数量(也就是 n 的值)不断增加,以及每个元素(正整数)的位数增多,可能出现的操作路径数量会呈现指数级的增长态势。例如,一个长度较大且每个元素都是多位数字的数组,要去穷举所有可能的每次删除一位数字的操作顺序,计算复杂度会变得极高,无论是时间成本还是空间成本都会变得难以承受,所以要解决该问题的关键在于找到一种高效的、能够避免大规模穷举的算法策略,来精准确定最少的操作步数。

三、思路

整体的解决思路是设计一种算法,能够巧妙地统计出每个数字变为 0 实际所需要的操作步数,然后汇总得到整个数组的最少总步数,避免去逐一列举所有可能的操作序列。

具体而言,利用了数字在变为 0 的过程中一个特性:数字当中的 0 位其实不需要专门去执行删除操作,因为在其他非 0 数字位被逐步删除的过程中,这些 0 最终也会自然地消失,使得数字变为 0。基于此特性,我们可以将数字先转换为字符串形式,通过对字符串进行操作来统计真正需要删除的非 0 数字位的数量,以此来确定让这个数字变为 0 所需要的操作步数。

然后遍历整个数组,针对每一个元素(正整数)都按照上述方法去计算其变为 0 所需的步数,并将这些步数依次累加起来,最终得到的总和就是把数组中所有数字都变为 0 所需要的最少操作步数。

一开始我并没有尝试自己写代码,而是问了豆包这个问题。不出意外给了我一个很“笨”的穷举方法。我又去问文心一言,给的答案也是大差不差的,我告诉他我的思路之后,他反驳了我认为我的方法是错误的。

难道这就是这道题分在“难”这一类的原因吗?

四、代码

以下是使用 Java 语言实现上述思路的代码示例:

public class Main {

    public static int solution(int n, int[] a) {
        int totalSteps = 0;
        // 遍历数组中的每一个数字
        for (int num : a) {
            String numStr = "" + num;
            // 剔除字符串中所有的 0 后,剩余字符串长度就是该数字变为 0 所需的操作步数
            totalSteps += numStr.replaceAll("0", "").length();
        }
        return totalSteps;
    }

    public static void main(String[] args) {
        // 测试样例 1
        System.out.println(solution(5, new int[]{10, 13, 22, 100, 30}) == 7);
        // 测试样例 2
        System.out.println(solution(3, new int[]{5, 50, 505}) == 4);
        // 测试样例 3
        System.out.println(solution(4, new int[]{1000, 1, 10, 100}) == 4);
    }
}

在上述代码中:

  • solution 方法里,首先初始化了一个变量 totalSteps 用于累计总的操作步数,初始值设为 0。接着通过增强型 for 循环遍历输入的数组 a 中的每一个数字 num。把每个数字 num 转换为字符串 numStr 后,利用 replaceAll 方法剔除其中所有的 0,而剩下的字符串长度就代表了让该数字变为 0 实际需要删除数字位的次数,也就是操作步数,将其累加到 totalSteps 中。当整个数组遍历完成后,totalSteps 中存储的就是把数组所有数字都变为 0 所需要的最少步数。

  • main 方法主要用于对 solution 方法进行简单测试,通过传入给定的不同测试样例数据,并将返回的结果和预期的正确结果(如样例 1 中预期为 7 等)进行比较,以布尔表达式的形式输出测试结果,以此来验证 solution 方法在不同输入情况下的正确性。

这样,通过上述代码就能高效地解决将给定数组中所有正整数通过逐位删除数字变为 0 并计算最少步数的问题了。