leetcode
leetcode 2401 ~ 2450
范围中美丽整数的数目

范围中美丽整数的数目

难度:

标签:

题目描述

You are given positive integers low, high, and k.

A number is beautiful if it meets both of the following conditions:

  • The count of even digits in the number is equal to the count of odd digits.
  • The number is divisible by k.

Return the number of beautiful integers in the range [low, high].

 

Example 1:

Input: low = 10, high = 20, k = 3
Output: 2
Explanation: There are 2 beautiful integers in the given range: [12,18]. 
- 12 is beautiful because it contains 1 odd digit and 1 even digit, and is divisible by k = 3.
- 18 is beautiful because it contains 1 odd digit and 1 even digit, and is divisible by k = 3.
Additionally we can see that:
- 16 is not beautiful because it is not divisible by k = 3.
- 15 is not beautiful because it does not contain equal counts even and odd digits.
It can be shown that there are only 2 beautiful integers in the given range.

Example 2:

Input: low = 1, high = 10, k = 1
Output: 1
Explanation: There is 1 beautiful integer in the given range: [10].
- 10 is beautiful because it contains 1 odd digit and 1 even digit, and is divisible by k = 1.
It can be shown that there is only 1 beautiful integer in the given range.

Example 3:

Input: low = 5, high = 5, k = 2
Output: 0
Explanation: There are 0 beautiful integers in the given range.
- 5 is not beautiful because it is not divisible by k = 2 and it does not contain equal even and odd digits.

 

Constraints:

  • 0 < low <= high <= 109
  • 0 < k <= 20

代码结果

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


/*
 * 使用Java Stream的思路:
 * 1. 使用IntStream遍历从low到high之间的每个整数。
 * 2. 通过filter筛选出满足条件的美丽整数。
 * 3. 使用count()方法计算美丽整数的数量。
 */
import java.util.stream.IntStream;

public class BeautifulNumbersStream {
    public static int countBeautifulNumbers(int low, int high, int k) {
        return (int) IntStream.rangeClosed(low, high)
                .filter(num -> {
                    int oddCount = 0;
                    int evenCount = 0;
                    int original = num;

                    while (num > 0) {
                        int digit = num % 10;
                        if (digit % 2 == 0) {
                            evenCount++;
                        } else {
                            oddCount++;
                        }
                        num /= 10;
                    }

                    // 检查是否奇数位和偶数位数量相等并且可以被k整除
                    return oddCount == evenCount && original % k == 0;
                })
                .count();
    }

    public static void main(String[] args) {
        int low = 10, high = 20, k = 3;
        System.out.println(countBeautifulNumbers(low, high, k)); // 输出: 2
    }
}

解释

方法:

题解采用了深度优先搜索(DFS)和记忆化搜索来解决问题。首先,将low和high转换为字符串,并在low前补0使其长度与high一致。这样可以确保在比较时位数相等。通过递归函数dfs来探索每个可能的数字,该函数通过六个参数来控制状态:当前处理的数字位置i,当前奇数位的数量cnt1,偶数位的数量cnt2,当前数字模k的余数cnt3,以及两个布尔值is_limit1和is_limit2分别表示当前是否受到low和high的限制。递归的基本思路是,对于每一位,根据是否受限制选择可能的数字范围进行遍历,并递归处理下一位。最终,当处理完所有位时,检查奇数位和偶数位数量是否相等以及是否能被k整除,来确定该数字是否美丽。

时间复杂度:

O(n^2 * k)

空间复杂度:

O(n^2 * k)

代码细节讲解

🦆
为什么解题思路选择使用深度优先搜索(DFS)而不是简单的迭代法来枚举每个数字?
使用DFS而不是迭代法的原因在于,问题的复杂性和约束条件。DFS允许我们在搜索过程中有效地应用剪枝,避免无效的枚举。例如,通过逐步构建数字并在不满足条件时立即停止进一步搜索,可以显著减少需要检查的数字总数。此外,迭代枚举每个数字在数字范围很大时将非常低效,特别是当涉及到多个约束(如位数的奇偶性和模k余数)时,DFS通过递归控制和状态传递可以更灵活地处理这些复杂的条件。
🦆
在实现DFS时,你是如何处理数字0的,尤其是在数字开头的情况?
在DFS实现中,处理数字0,特别是在数字开头的情况,通过确保数字长度与high相同来进行。这是通过将low数字前补0实现的,确保在递归过程中每一位都能被考虑到,即使它是0。在递归函数中,通过参数is_limit1和is_limit2控制数字是否可以取0,尤其是在首位。如果is_limit1为true且当前位是最低位,则可以从0开始;否则,如果不是首位或没有限制,则可以自由选择0到9之间的任何数字。
🦆
为什么需要在递归函数中使用两个布尔值is_limit1和is_limit2来限制数字的范围?具体是如何实现的?
在递归函数中使用is_limit1和is_limit2这两个布尔值是为了确保生成的数字在指定的low和high范围内。is_limit1控制生成数字不低于low,is_limit2确保不超过high。具体实现方式是,当递归到某一位时,如果是受限状态(即is_limit1或is_limit2为true),则这一位数字的选取会受到low或high对应位的限制:只能从low的当前位或到high的当前位之间选择。如果不受限,则可以自由选择0到9任意数字。这种方法可以精确控制数字的生成,避免无效的搜索。
🦆
记忆化搜索的关键是什么?你是如何确定记忆化的状态和参数的?
记忆化搜索的关键是避免重复计算已经求解过的状态,从而提高算法效率。在本题中,记忆化的状态和参数包括当前位的位置i,奇数位的数量cnt1,偶数位的数量cnt2,以及当前数字模k的余数cnt3,还有两个布尔值is_limit1和is_limit2表示是否受到low和high的限制。通过缓存这些状态的结果,当递归调用遇到相同的状态时,可以直接返回之前计算的结果,避免了重复的计算工作。这种方法特别适用于本题,因为数字的每一位选择都可能引起状态的变化,且状态空间大,容易产生重复。

相关问题