伴学笔记四:数字魔法的加一操作 | 豆包MarsCode AI刷题

72 阅读5分钟

一、问题描述

数字魔法师小U发现了一种特殊的数字变换魔法。这个魔法可以对一个数字字符串进行"进位"操作。每次操作规则如下:

  • 对字符串中的每个数字进行加一操作
  • 当某位数字为9时,加一后变成 0,并在前面补 1

例如:

  • "798" 经过一次操作变成 "8109"(7→8, 9→0并向前增加一个1, 8→9)
  • "999" 经过一次操作变成 "101010"

现在给定一个数字字符串 num_str(长度为n)和操作次数 k,请计算经过 k 次操作后得到的最终结果。由于结果可能非常大,请将答案对 1000000007 (10^9 + 7) 取模。

1. 输入

  • 第一行包含两个整数 n 和 k(1 ≤ n ≤ 50, 1 ≤ k ≤ 100)
  • 第二行包含一个长度为n的数字字符串 num_str,仅由数字0-9组成

2. 返回

  • 返回一个整数,表示最终结果对 1000000007 取模后的值

二、整体做题思路

这段Java代码定义了一个名为 solution 的方法,该方法接受三个参数:一个整数 n(在当前代码逻辑中未实际使用)、一个整数 k 和一个表示数字的字符串 numStr。其主要功能是对给定的数字字符串按照特定规则进行操作,这个规则是对字符串表示的数字逐位加一操作 k 次,最后将结果对一个大整数(1000000007)取余并返回余数的整数值。在主函数 main 中,通过调用 solution 方法并使用一些预定义的测试用例来验证方法的正确性。

三、编写过程与思路分析

  1. 数据结构初始化
LinkedList<Integer> list = new LinkedList<>();
for (char word : numStr.toCharArray()) {
    int num = word - '0';
    list.add(num);
}

首先创建了一个 LinkedList 类型的列表 list,用于存储数字字符串中的每个数字。通过遍历输入的数字字符串 numStr,将每个字符转换为对应的数字(通过将字符的ASCII码减去字符 '0' 的ASCII码),然后将这些数字逐个添加到链表 list 中。这样就将输入的数字字符串以数字形式存储在链表中,方便后续操作。

  1. 链表反转操作
java.util.Collections.reverse(list);

在进行数字的逐位操作之前,先将链表反转。这可能是为了方便从最低位(个位)开始进行逐位加一的操作。因为在数字的常规运算中,从低位开始计算更为直观。例如,对于数字 123,先反转得到 321,这样在后续的逐位操作中,可以先处理个位,然后依次处理高位,符合数字运算的习惯。

  1. 逐位加一操作
for(int j = 0; j < k; j++){
    for (int i = 0; i < list.size(); i++) {
        int value = list.get(i) + 1;
        if (value <= 9) {
            list.set(i, value);
        } else if (value == 10) {
            list.set(i, 0);
            list.add(i + 1, 1);
            i++;
        }
    }
}

这部分是代码的核心逻辑之一。外层循环控制逐位加一操作的次数,由参数 k 决定。内层循环遍历链表中的每个元素(即数字字符串中的每一位数字)。对于每个数字,将其加一得到新的值 value。如果 value 小于等于9,直接将链表中的该位数字更新为 value。如果 value 等于10,说明该位数字进位了,此时将该位数字设置为0,并在该位的下一位(i+1)插入数字1,表示进位。同时,为了避免再次处理刚插入的数字1,将索引 i 自增1。通过这样的操作,实现了对数字字符串表示的数字逐位加一的功能。

  1. 链表再次反转操作
java.util.Collections.reverse(list);

在完成逐位加一操作后,将链表再次反转。这是因为之前为了方便逐位操作而进行了反转,现在需要将数字恢复到正常的顺序,以便后续构建正确的数字。

  1. 构建大整数并取余操作
StringBuilder sb = new StringBuilder();
for (Integer num : list) {
    sb.append(num);
}
BigInteger number = new BigInteger(sb.toString());
BigInteger text = new BigInteger("1000000007");
return number.remainder(text).intValue();

首先创建一个 StringBuilder 对象 sb,然后遍历反转后的链表,将每个数字添加到 sb 中,从而构建一个表示最终结果的字符串。接着,使用这个字符串创建一个 BigInteger 对象 number。同时创建一个表示固定值(1000000007)的 BigInteger 对象 text。最后,使用 remainder 方法计算 number 除以 text 的余数,并将结果转换为整数类型(intValue)返回。选择使用 BigInteger 是因为在处理较大数字的运算时,普通的整数类型可能会出现溢出问题,而 BigInteger 可以处理任意大小的整数。

  1. 主函数中的测试逻辑
public static void main(String[] args) {
    int result1 = solution(3, 1, "798");
    System.out.println(result1 == 8109);

    int result2 = solution(4, 1, "8109");
    System.out.println(result2 == 92110);

    int result3 = solution(5, 1, "92110");
    System.out.println(result3 == 103221);
}

在主函数中,通过调用 solution 方法并传入不同的参数进行测试。对于每个测试用例,将 solution 方法的返回值与预期值进行比较(通过 == 比较,这里假设预期值是准确的并且代码逻辑正确时结果应该严格相等),并将比较结果输出到控制台。这样可以直观地看到代码在给定测试用例下的运行结果是否符合预期,有助于调试和验证代码的正确性。

四、总结

这段代码通过对数字字符串的存储、转换、运算以及结果的处理,实现了对给定数字按照特定规则进行操作并返回特定余数的功能,同时在主函数中提供了简单的测试逻辑来验证方法的正确性。