题解:学而思编程 拼数字

【题目来源】

学而思编程:拼数字

【题目描述】

小猴喜欢玩数字卡片游戏,每张卡片上的数字都是 \(0∼9\) 中的任意一个。

小猴已经积累了很多的数字卡片,并且 \(0∼9\) 的数字卡片小猴各有 \(n\) 张。

小猴想用这些卡片来拼从 \(1\) 开始的一些连续正整数,他想要知道自己手里的卡片能从 \(1\) 开始最大能拼到多少。

例如,小猴现在 \(0∼9\) 的数字卡片各有 \(3\) 张,那么小猴最大可以拼到 \(10\),因为拼 \(11\) 时候数字 \(1\) 卡片只有 \(1\) 张了,不够拼出 \(11\)

【输入】

一行一个整数 \(n\)

【输出】

一行一个整数,表示小猴最大可以拼到的整数。

【输入样例】

1

【输出样例】

9

【核心思想】

  1. 问题分析:给定 \(0\)\(9\) 的数字卡片各 \(n\) 张,从 \(1\) 开始连续拼接正整数,求最大能拼到多少。这是一个贪心模拟 + 逐位检查问题,关键在于从 \(1\) 开始逐个尝试,每次消耗对应数字的卡片,直到某个数字无法拼出。

  2. 算法选择

    • 贪心递增:从 \(1\) 开始逐个尝试,能拼出则继续,不能则停止
    • 逐位消耗:将每个数字的各位分解,检查并消耗对应卡片
  3. 关键步骤

    • 初始化
      • 读取 \(n\)
      • num[i] = n\(i\)\(0\)\(9\)):每种数字卡片初始 \(n\)
    • 逐个尝试
      • ans = 1
      • check(ans) 为真时循环:ans++
    • 检查函数 check(x)
      • x > 0 时循环:
        • y = x % 10:取出最低位数字
        • num[y]--:消耗该数字卡片
        • num[y] < 0:返回 false(卡片不足)
        • x /= 10:去掉最低位
      • 返回 true
    • 输出 ans - 1(最后一个能拼出的数字)
  4. 时间/空间复杂度

    • 时间复杂度:\(O(ans \times \log ans)\)\(ans\) 为答案,每个数字最多 \(\log ans\)
    • 空间复杂度:\(O(1)\),仅需 \(10\) 个计数变量
  5. 贪心模拟的核心思想

    • 连续性约束:必须从 \(1\) 开始连续拼,不能跳过,因此贪心逐个尝试是最优策略
    • 卡片消耗不可逆check 函数中直接修改 num 数组,模拟真实消耗过程,一旦失败无法回退
    • 逐位分解:通过 %10/10 逐位提取数字,独立检查每种卡片的剩余量
    • 终止条件:当某个数字的卡片耗尽且该数字 needed 时,check 返回 false,循环终止
    • 适用于"资源有限 + 连续构造"类问题,贪心模拟直观且能保证最优性(因为必须连续)

【算法标签】

模拟

【代码详解】

#include <bits/stdc++.h>
using namespace std;
#define int long long
int n, num[10];  // 数字数量限制n,数字0-9的剩余数量数组
bool check(int x)  // 检查能否用剩余数字组成数字x
{
    while (x>0)  // 逐位检查
    {
        int y = x % 10;  // 取出最低位
        num[y]--;  // 该数字使用次数减1
        if (num[y]<0) return false;  // 如果数字用完,返回false
        x /= 10;  // 去掉最低位
    }
    return true;  // 可以组成数字x
}
signed main()  // 主函数
{
    cin >> n;  // 输入每个数字最多可用次数
    for (int i=0; i<=9; i++) num[i] = n;  // 初始化所有数字的剩余数量
    int ans = 1;  // 从数字1开始尝试
    while (check(ans)==true) ans++;  // 不断尝试更大的数字
    cout << ans - 1 << endl;  // 输出能组成的最大数字
    return 0;  // 程序正常结束
}

【运行结果】

1
9
posted @ 2026-07-05 14:42  团爸讲算法  阅读(6)  评论(0)    收藏  举报