leetcode
leetcode 2551 ~ 2600
统计强大整数的数目

统计强大整数的数目

难度:

标签:

题目描述

You are given three integers start, finish, and limit. You are also given a 0-indexed string s representing a positive integer.

A positive integer x is called powerful if it ends with s (in other words, s is a suffix of x) and each digit in x is at most limit.

Return the total number of powerful integers in the range [start..finish].

A string x is a suffix of a string y if and only if x is a substring of y that starts from some index (including 0) in y and extends to the index y.length - 1. For example, 25 is a suffix of 5125 whereas 512 is not.

 

Example 1:

Input: start = 1, finish = 6000, limit = 4, s = "124"
Output: 5
Explanation: The powerful integers in the range [1..6000] are 124, 1124, 2124, 3124, and, 4124. All these integers have each digit <= 4, and "124" as a suffix. Note that 5124 is not a powerful integer because the first digit is 5 which is greater than 4.
It can be shown that there are only 5 powerful integers in this range.

Example 2:

Input: start = 15, finish = 215, limit = 6, s = "10"
Output: 2
Explanation: The powerful integers in the range [15..215] are 110 and 210. All these integers have each digit <= 6, and "10" as a suffix.
It can be shown that there are only 2 powerful integers in this range.

Example 3:

Input: start = 1000, finish = 2000, limit = 4, s = "3000"
Output: 0
Explanation: All integers in the range [1000..2000] are smaller than 3000, hence "3000" cannot be a suffix of any integer in this range.

 

Constraints:

  • 1 <= start <= finish <= 1015
  • 1 <= limit <= 9
  • 1 <= s.length <= floor(log10(finish)) + 1
  • s only consists of numeric digits which are at most limit.
  • s does not have leading zeros.

代码结果

运行时间: 32 ms, 内存: 16.8 MB


/*
 * 思路:
 * 1. 使用Java Stream来简化对[start..finish]区间内整数的遍历。
 * 2. 使用filter函数过滤出满足条件的强大整数。
 * 3. 通过count方法统计数量。
 */

import java.util.stream.IntStream;

public class PowerfulIntegersStream {
    public static int countPowerfulIntegers(int start, int finish, int limit, String s) {
        return (int) IntStream.rangeClosed(start, finish)
                .filter(x -> isPowerful(x, limit, s))
                .count();
    }

    private static boolean isPowerful(int x, int limit, String s) {
        String xStr = Integer.toString(x);
        return xStr.endsWith(s) && xStr.chars().allMatch(c -> Character.getNumericValue(c) <= limit);
    }

    public static void main(String[] args) {
        int start = 15;
        int finish = 215;
        int limit = 6;
        String s = "10";
        System.out.println(countPowerfulIntegers(start, finish, limit, s));
    }
}

解释

方法:

题解首先定义了一个内部函数 count(num),用于计算从 1 到 num 范围内所有强大整数的数量。该函数通过将数字 num 转换为字符串,并从高位到低位逐位检查,确定每位数字是否满足小于等于 limit 的条件。对于每一位,如果大于 limit,后续的所有数字组合均不符合条件,直接返回当前计数结果;如果小于等于 limit,则继续检查下一位。该函数的核心在于逐位确定数字的范围,特别是对于最后的 l 位(s 的长度),需要检查是否恰好等于 s 来决定是否增加计数。整体解法通过计算 count(finish) - count(start-1) 来得到区间 [start, finish] 内强大整数的数量,利用了前缀和的思想。

时间复杂度:

O(m) where m is the number of digits in the largest number between start and finish.

空间复杂度:

O(1)

代码细节讲解

🦆
为什么在函数`count(num)`中,需要将`limit`的值加1进行计算?
在`count(num)`函数中,增加`limit`值的1是用来将数字的最大可能值(即`limit`)纳入计算范围内。因为在计算数字组合的可能性时,我们需要考虑所有小于等于`limit`的数字(包括`limit`本身)。例如,如果`limit`是5,我们需要考虑的数字是0到5,共6个数字。将`limit`加1是为了方便使用0到`limit`这`limit+1`个数字进行组合的计算,避免在循环和条件判断中进行额外的边界处理。
🦆
在计算`power`时,为什么选择的是`pow(limit, len(num)-l)`,这里的`len(num)-l`代表什么含义?
`len(num)-l`代表的是在检查数字`num`时,除去末尾`s`长度`l`之后的数字位数。`power`在这里表示每一位数字(从最高位到`s`开始的位置)可以代表的数值范围。例如,如果`num`是123456,且`s`的长度是3,则`len(num)-l`计算的是123这三个数字的位数。`pow(limit, len(num)-l)`计算的是从最高位到`s`开始的位置,每一位数字可以变化的总数,即每位数字都可以从0至`limit`变化,共有`pow(limit, len(num)-l)`种可能。
🦆
在`count`函数中,如果当前位的数字小于`limit`,为什么累加的是`int(c)*power`而不是其他值?这样的计算逻辑是如何确保正确性的?
在`count`函数中,`int(c)*power`的计算是为了计算当前数字位`c`对总数的贡献。这里,`power`表示当前位后面的每一位数字可以取的所有可能值的总数(即权重)。例如,如果当前位是百位,且`limit`为5,那么每增加1百(如从100到200),后面的两位数字可以有`pow(limit, 2)`种可能的组合。当当前位的数字`c`小于`limit`时,表示该位可以自由取值,而且每增加1,后面的组合数就增加`power`次。这种计算逻辑确保了从当前位开始到最低位的所有可能的数字组合都被正确计算,从而确保了总数的正确性。

相关问题