【LeetCode 902】最大为 N 的数字组合 - 详细题解与数位组合思路

【LeetCode 902】最大为 N 的数字组合 - 详细题解与数位组合思路

题目描述

给定一个按升序排列的数字数组 digits 和一个整数 n,返回用 digits 中的数字组合出的、小于或等于 n 的正整数的个数。


解题思路(数位 DP / 组合计数)

我们可以将统计满足条件的数字个数分为 两大类 进行讨论:

1. 位数小于 n 的数字

如果构造的数字位数比 n 的位数(设为 lenlenlen)小,那么无论怎么选,数值一定小于 n。

  • 长度为 1 的数字个数:m1m^1m1
  • 长度为 2 的数字个数:m2m^2m2
  • ...
  • 长度为 len−1len-1len−1 的数字个数:mlen−1m^{len-1}mlen−1

我们可以直接通过循环累加 m1+m2+⋯+mlen−1m^1 + m^2 + \dots + m^{len-1}m1+m2+⋯+mlen−1。

2. 位数等于 n 的数字

将 n 转化为字符串 sss,逐位(从高位到低位 iii)进行比较:

  1. 当前位选择小于 sisisi 的数字 :
    • 此时后续剩余的 len−1−ilen - 1 - ilen−1−i 个位置可以任意选择 digits 中的数字。
    • 方案增加数:m(len−1−i)m^{(len - 1 - i)}m(len−1−i)。
  2. 当前位选择等于 sisisi 的数字 :
    • 标记当前位可以匹配(same = true),并继续考察下一位 i+1i+1i+1。
  3. 当前位没有可选的数字小于或等于 sisisi :
    • 如果 digits 中没有与 sisisi 相同的数字,说明无法继续向后构造与 n 相同的数,此时直接返回累加结果。

如果成功匹配完所有的 lenlenlen 位,说明可以构造出一个完全等于 n 的数字,最终答案额外 +1+1+1。


C++ 代码实现

cpp 复制代码
class Solution {
public:
    int atMostNGivenDigitSet(vector<string>& digits, int n) {
        string s = to_string(n);
        int m = digits.size();
        int len = s.size();
        long long ans = 0;
        
        // 1. 统计位数小于 len 的所有组合数
        long long tem = 1;
        for (int i = 1; i < len; i++) {
            tem *= m;
            ans += tem;
        }

        // 2. 统计位数等于 len 且小于等于 n 的组合数
        for (int i = 0; i < len; i++) {
            bool same = false;
            for (auto &d : digits) {
                if (d[0] < s[i]) {
                    // 当前位选小于 s[i] 的数,后续位可任意组合
                    long long tem2 = 1;
                    for (int j = i + 1; j < len; j++) {
                        tem2 *= m;
                    }
                    ans += tem2;
                } else if (d[0] == s[i]) {
                    // 找到相等的数字,标记可以继续比对下一位
                    same = true;
                }
            }
            // 如果 digits 中没有与 s[i] 相等的数字,无法继续向前匹配,直接返回
            if (!same) {
                return ans;
            }
        }

        // 遍历完成说明可以构造出完全等于 n 的数字
        return ans + 1;
    }
};

复杂度分析

  • 时间复杂度 :O(len×m)\mathcal{O}(len \times m)O(len×m),其中 lenlenlen 为数字 nnn 的十进制位数(不超过 10),mmm 为 digits 数组的大小。循环层数和数字位数成正比,运行耗时极低(可达 0 ms)。
  • 空间复杂度 :O(len)\mathcal{O}(len)O(len),仅用于将整数 nnn 转换为字符串存储。
相关推荐
倒头就睡的小比特5 天前
算法竞赛C++常用的STL
c++·算法
小羊没烦恼!5 天前
初探性能优化——2个月到4小时的性能提升
java·开发语言·windows·算法·c#
猎头南楼6 天前
知识社区推荐系统实践:新用户冷启动与长短期兴趣建模的挑战 资深推荐算法工程师
人工智能·深度学习·算法·机器学习
m0_547486666 天前
《数据结构教程》全套 PPT课件2026
数据结构
旖旎夜光6 天前
力控面试题 01.01: 判定字符是否唯一(位运算) —— 题解
c++·学习·算法·leetcode·力控
wzdark6 天前
大规模并行计算中的负载均衡算法研究4
算法
Because_of_Her16 天前
并查集-听课笔记
笔记·算法·并查集
码流子6 天前
高速公路安全监测实践:碰撞监测预警+物联网底座,从感知到处置的闭环
大数据·人工智能·物联网·算法·架构
another heaven6 天前
【算法/C++ MD5算法能否逆解码?原理、C++实现与同类哈希算法对比】
c++·算法·哈希算法
wzdark6 天前
从算法设计模式看编程思维的抽象能力4
算法