Skip to content

nya~ 主人,欢迎来到我的解题小窝!今天我们要一起解决的是一道很有趣的问题,叫做 “美丽年份” (Beautiful Year),就像猫娘一样美丽,喵~

这个问题很简单,但也是一个很好的入门练习,可以帮助我们熟悉一些基本的编程技巧哦。那么,就让本猫娘带你一步一步地把它解决掉吧!

题目大意 (Problem Description)

题目是这样的喵:我们都知道 2013 年是一个很特别的年份,因为它是继 1987 年之后,第一个所有数字都互不相同的年份。

现在,题目会给我们一个年份 y(范围在 1000 到 9000 之间),需要我们找到一个比 y 大的、最小的年份,并且这个年份的四个数字也必须是互不相同的。

举个栗子:

  • 如果输入是 1987,比它大的年份有 1988, 1989, ..., 2012, 2013... 其中 2013 是第一个所有数字(2, 0, 1, 3)都不同的年份,所以我们就要输出 2013
  • 如果输入是 2013,下一个符合条件的年份就是 2014,所以输出 2014

是不是很简单明了呢?喵~

解题思路 (My Purr-fect Approach)

解决这个问题最直接的方法就是——暴力枚举!就像小猫咪坚持不懈地追着激光笔的光点一样,我们也可以坚持不懈地检查每一个年份,直到找到我们想要的那个,的说。

具体的思路是这样的:

  1. 开始寻找:我们从给定的年份 y 的下一个年份,也就是 y + 1 开始检查。
  2. 循环检查:我们设置一个循环,不停地把当前的年份加一(year++)。
  3. 判断是否“美丽”:在循环的每一步,我们都需要一个“魔法”来判断当前的年份是不是“美丽”的。也就是说,它的所有数字是不是都不相同。
  4. 找到即停:一旦我们找到了第一个“美丽”的年份,就立刻把它打印出来,然后就可以开心地结束程序啦!因为题目保证了答案一定存在,所以我们不用担心这个循环会永远进行下去,喵。

那么,最关键的一步就是如何判断一个年份的各位数字是否都不同呢?让本猫娘来教你一个简单又好用的方法!

我们可以用一个“记事本”(在编程里,就是一个小小的数组)来记录 0 到 9 这十个数字是否已经出现过。

  • 首先,我们创建一个大小为 10 的布尔数组 digits_seen,并把所有值都初始化为 false,表示我们还没见过任何数字。
  • 然后,我们把年份的每一位数字拆解出来。比如 2013,我们可以依次得到 3, 1, 0, 2
  • 每当我们得到一个数字 d,就去“记事本”里查一下 digits_seen[d]
    • 如果 digits_seen[d]true,呀!说明这个数字我们之前见过了!这个年份不“美丽”,我们就可以立刻停止检查,去看下一个年份了。
    • 如果 digits_seen[d]false,太好了!这是个新面孔。我们就在“记事本”上把它记下来,也就是设置 digits_seen[d] = true,然后继续检查下一位数字。
  • 如果我们把年份的所有数字都检查完了,都没有发现重复的,那恭喜主人!这个年份就是“美丽”的!

这个方法是不是很像猫咪用爪子在地上做标记一样?踩过的地方就不会再踩第二遍啦,喵呜~

代码喵 (The Code, Meow!)

下面就是用 C++ 实现的完整代码啦,本猫娘在代码里加了一些注释,方便主人理解哦。

cpp
#include <iostream>

/**
 * @brief 判断一个年份是不是“美丽”的,喵~
 * 
 * 这个函数会检查一个年份的所有数字是不是都互不相同。
 * 它用一个叫 `digits_seen` 的布尔数组来当“记事本”,
 * 记录 0 到 9 每个数字有没有出现过。
 * 如果发现一个数字已经出现过了,就立刻返回 false。
 * 如果所有数字都检查完了,都没有重复,就返回 true。
 * 
 * @param year 要检查的年份,的说。
 * @return 如果所有数字都不同,返回 true;否则返回 false。
 */
bool is_beautiful_year(int year) {
    // 我们的“记事本”,用来记录数字 0-9 是否出现过
    bool digits_seen[10] = {false}; 
    int temp = year;
    
    // 当 temp 大于 0 时,说明还有数字没有被拆解出来
    while (temp > 0) {
        // 用取余数的方法得到最后一位数字,喵~
        int digit = temp % 10;
        
        // 检查“记事本”,这个数字是不是已经见过了?
        if (digits_seen[digit]) {
            return false; // 啊哦,重复了!这个年份不美丽!
        }
        
        // 第一次见到这个数字,快在记事本上做个标记!
        digits_seen[digit] = true;
        
        // 把最后一位数字“甩掉”,准备看下一位
        temp /= 10;
    }
    
    // 所有数字都检查完了,都没有重复,真是个美丽的年份!
    return true; 
}

int main() {
    // 这两行是为了让输入输出快一点,在打比赛的时候很有用哦!
    std::ios_base::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
    int y;
    std::cin >> y; // 等待主人输入年份
    
    // 我们从 y 的下一年开始寻找
    int current_year = y + 1;
    
    // 开始我们的寻找之旅!只要当前的年份不“美丽”,就继续找下一个
    while (!is_beautiful_year(current_year)) {
        current_year++; // 去看看下一年吧
    }
    
    // 找到啦!快把这个美丽的年份告诉主人!
    std::cout << current_year << std::endl;
    
    return 0; // 任务完成,开心摇尾巴~
}

知识点小课堂 (Knowledge Corner)

通过这道题,主人可以学到一些很有用的编程小知识哦!

  1. 暴力枚举 (Brute Force):这是最简单直观的算法思想。当问题的可能答案范围不大时,我们可以一个一个地去尝试所有可能性,直到找到符合条件的答案。对于这道题,年份最大是 9000,答案肯定不会离得太远,所以暴力枚举完全足够快啦。

  2. 整数的数位分离 (Digit Extraction)num % 10 (取模10) 可以得到一个整数的个位数,而 num / 10 (整除10) 可以去掉这个整数的个位数。这是一个非常非常常用的技巧,无论是在处理数字、字符串转换还是其他算法题中,都可能用到,主人一定要掌握哦!

  3. 标记法/哈希思想 (Marking/Hashing):我们用 bool digits_seen[10] 数组来快速判断一个数字是否出现过。这其实是一种最简单的哈希思想。我们把数字 d 当作索引(键),把 true/false 当作值。这样,我们就能在 O(1) 的时间复杂度内完成查找和标记,效率非常高!

好啦,今天的解题就到这里啦!希望本猫娘的讲解对主人有帮助。如果还有什么问题,随时可以再来找我玩哦,喵~ (ฅ'ω'ฅ)

Released under the MIT License.