leetcode
leetcode 2301 ~ 2350
统计整数数目

统计整数数目

难度:

标签:

题目描述

You are given two numeric strings num1 and num2 and two integers max_sum and min_sum. We denote an integer x to be good if:

  • num1 <= x <= num2
  • min_sum <= digit_sum(x) <= max_sum.

Return the number of good integers. Since the answer may be large, return it modulo 109 + 7.

Note that digit_sum(x) denotes the sum of the digits of x.

 

Example 1:

Input: num1 = "1", num2 = "12", min_sum = 1, max_sum = 8
Output: 11
Explanation: There are 11 integers whose sum of digits lies between 1 and 8 are 1,2,3,4,5,6,7,8,10,11, and 12. Thus, we return 11.

Example 2:

Input: num1 = "1", num2 = "5", min_sum = 1, max_sum = 5
Output: 5
Explanation: The 5 integers whose sum of digits lies between 1 and 5 are 1,2,3,4, and 5. Thus, we return 5.

 

Constraints:

  • 1 <= num1 <= num2 <= 1022
  • 1 <= min_sum <= max_sum <= 400

代码结果

运行时间: 44 ms, 内存: 17.9 MB


/*
 * Solution using Java Stream to count the number of 'good integers' between num1 and num2.
 * This solution leverages the use of streams for cleaner code and functional style.
 * The definition of a 'good integer' and the required conditions remain the same.
 */
import java.math.BigInteger;
import java.util.stream.Stream;

public class GoodIntegersStream {
    private static final int MOD = 1_000_000_007;

    public int countGoodIntegers(String num1, String num2, int min_sum, int max_sum) {
        BigInteger lower = new BigInteger(num1);
        BigInteger upper = new BigInteger(num2);

        return Stream.iterate(lower, n -> n.compareTo(upper) <= 0, n -> n.add(BigInteger.ONE))
                .mapToInt(this::getDigitSum)
                .filter(sum -> sum >= min_sum && sum <= max_sum)
                .map(sum -> 1)
                .reduce(0, (a, b) -> (a + b) % MOD);
    }

    private int getDigitSum(BigInteger number) {
        return number.toString().chars().map(c -> c - '0').sum();
    }
}

解释

方法:

The solution uses a digit dynamic programming approach to efficiently count numbers within a specific range whose digit sum falls between given bounds. It considers two main functions: 1) 'ndn(n, dsum)', which calculates how many n-digit numbers have a digit sum exactly equal to 'dsum'. 2) 'ddn(num, max_sum)', which calculates the count of numbers up to 'num' that have a digit sum of at most 'max_sum'. The main idea is to count the numbers satisfying the conditions up to 'num2' and subtract the count of numbers up to 'num1' - 1 (thus counting numbers between 'num1' and 'num2'), and adjust this for the specified digit sum range.

时间复杂度:

O(D^2 * 10 * max_sum) where D is the number of digits in 'num2'. This complexity stems from the iteration over all possible first digits and recursive processing for each subsequent digit.

空间复杂度:

O(D * max_sum), which accounts for the maximum depth of recursion multiplied by the range of digit sums cached.

代码细节讲解

🦆
在解决方案中,`ndn(n, dsum)`函数的基本情况是什么意义,为什么当`n == 0`时返回1?
在`ndn(n, dsum)`函数中,基本情况是当`n == 0`时返回1。这表示没有更多的数字可以选择,如果此时`dsum`也正好为0,则唯一可能的“数字”是数值0(没有任何数字组成的数)。因此,这里返回1表示存在一种方法(即选择数字0)使得数字总和为0。如果`dsum`不为0,会由函数其他部分返回0,因为无法通过非零数量的数字达到非零的`dsum`。
🦆
对于`ddn(num, max_sum)`函数,如何确保所有可能的数位组合都被正确考虑,特别是在处理数字的最高位时?
在`ddn(num, max_sum)`函数中,它首先考虑所有小于给定数字`num`的最高位的可能数字,并使用`ndn`递归计算每种情况的结果。对每个小于最高位的数字,它计算剩下的位数可以形成的所有数字和。这确保了除了最高位的所有其他位的组合都被考虑到。接着,函数递归地考虑最高位数字正好等于`num`的第一个数字的情况,并处理剩余的数字。这种方法确保了从最高位到最低位的每一位都被正确地考虑到,从而可以生成所有小于或等于`num`的数字。
🦆
解释为什么需要在计算`num1`对应的好整数时,将`num1`减去1,并在后续处理中如何确保这种调整的正确性?
在计算区间`[num1, num2]`内满足条件的数字数量时,需要将`num1`减去1,因为`ddn`函数计算的是小于或等于给定数字的所有可能的数字。如果不减1,那么计算结果会包括`num1`,而我们需要的是从`num1`开始的区间。通过将`num1`减去1并计算到`num1-1`为止的数字,然后从`num2`的结果中减去这个结果,我们可以确保区间是正确的`[num1, num2]`。这种处理确保了在边界的处理上,我们不会错过或多计算任何数字。
🦆
在`ddn`函数中,递归调用遇到的边界条件`max_sum < 0`是如何影响结果的,为什么返回0?
在`ddn`函数中,如果`max_sum < 0`,这意味着不可能有任何有效的数字组合其数位和为一个负数。因此,在这种情况下直接返回0是合理的,表示不存在任何数位组合能够满足数位和小于0的条件。这是一个必要的边界条件检查,它阻止了无效计算的进行,并确保递归能在合适的条件下正确终止。

相关问题