Skip to content

喵哈~!主人,今天我们来看一道超级可爱的题目,叫做 "Pangram" 呢。别看它名字有点怪,其实是个很简单的字符串问题哦。让本猫娘来给你好好讲讲吧,喵~

题目大意

这道题是关于一种叫做 “全字母句” (Pangram) 的东西,听起来是不是很厉害的样子?一个全字母句,就是指一个句子或者单词,它把字母表里所有的字母(在这个问题里就是英语字母 a 到 z)都至少包含了一次,喵。

题目会给我们一个字符串,里面有大写和小写的英文字母。我们需要判断这个字符串是不是一个全字母句。大小写是不区分的哦,也就是说 'a' 和 'A' 都算是字母 'a'。如果字符串包含了从 'a' 到 'z' 的所有26个字母,我们就输出 "YES",否则就输出 "NO",就这么简单呢。

举个栗子:

  • "toosmallword" -> 里面缺了好多字母,所以是 "NO"。
  • "TheQuickBrownFoxJumpsOverTheLazyDog" -> 这句话可是非常有名的全字母句哦,它包含了所有26个字母,所以是 "YES"。

解题方法

要判断是不是全字母句,最直接的思路就是检查从 'a' 到 'z' 这26个字母是不是都在字符串里出现过,对吧?

本猫娘的思路是这样的,喵~:

  1. 一个快速的小判断:一个合格的全字母句,至少得有26个字符才能装下所有字母呀。所以,如果给我们的字符串长度 n 小于26,那它肯定不是全字母句啦!直接输出 "NO" 就可以跑路了,嘿嘿。

  2. 标记字母是否出现:我们需要一个东西来记录哪些字母已经出现过了。一个大小为26的布尔数组 letters_found 就很合适!数组的第0个位置对应字母'a',第1个位置对应'b',以此类推,直到第25个位置对应'z'。一开始,把它们全都设为 false,表示我们一个字母都还没找到呢。

  3. 遍历字符串:接下来,我们一个一个地看输入字符串里的每个字符。

    • 因为题目不区分大小写,所以不管拿到的是大写还是小写,我们都先把它统一转换成小写字母。比如 'A' 变成 'a','B' 变成 'b'。
    • 然后,根据这个小写字母,找到它在布尔数组里对应的位置(比如 小写字母 - 'a'),然后把那个位置的值改成 true。这就像是在小本本上打个勾,表示“这个字母我找到啦!”
  4. 最终检查:等我们把整个字符串都检查完之后,再回头看看我们的布尔数组小本本。从头到尾检查一遍,如果发现有任何一个位置的值还是 false,那就说明对应的那个字母从没出现过,呜呜... 这就不是全字母句,输出 "NO"。

  5. 完美收官:如果检查完整个布尔数组,发现所有位置都是 true,那就太棒啦!说明所有26个字母都到齐了,这就是一个完美的全字母句!输出 "YES",任务完成,喵~!

题解代码

这是用 C++ 实现的代码,本猫娘加上了中文注释,方便主人理解哦。

cpp
#include <iostream>
#include <string>
#include <vector>
#include <cctype> // 包含 tolower 函数,用来转换小写字母
#include <set>    // 虽然这个解法没用 set,但它也是一种很好的选择哦

// 主函数,程序从这里开始执行喵
int main() {
    // 这两行是为了让输入输出更快一点,是竞赛中的一个小技巧呢
    std::ios_base::sync_with_stdio(false);
    std::cin.tie(nullptr);

    int n;
    // 读取字符串的长度
    std::cin >> n;
    std::string s;
    // 读取字符串本身
    std::cin >> s;

    // 一个小小的优化:如果字符串长度小于26,肯定凑不齐所有字母,直接说NO
    if (n < 26) {
        std::cout << "NO\n";
        return 0; // 程序结束
    }

    // 创建一个大小为26的布尔向量,用来记录a-z是否出现过
    // 初始值都是 false,表示都还没找到
    std::vector<bool> letters_found(26, false);

    // 遍历输入的字符串 s 中的每一个字符 ch
    for (char ch : s) {
        // 不管字符是大写还是小写,都统一转成小写
        char lower_ch = std::tolower(ch);
        
        // 计算这个小写字母对应的索引 (比如 'a' -> 0, 'b' -> 1)
        // 然后把 letters_found 数组中对应位置标记为 true
        letters_found[lower_ch - 'a'] = true;
    }

    // 遍历我们的标记数组 letters_found
    for (bool found : letters_found) {
        // 如果发现有任何一个字母没有被找到 (标记仍然是 false)
        if (!found) {
            // 那就说明这不是一个全字母句,输出 "NO" 然后结束程序
            std::cout << "NO\n";
            return 0;
        }
    }

    // 如果循环顺利结束,说明所有字母都被找到了!
    // 这就是一个全字母句,输出 "YES"
    std::cout << "YES\n";

    return 0; // 优雅地结束程序,喵~
}

知识点介绍

这道题虽然简单,但也用到了几个很有用的小知识点呢,主人快来学习一下!

  1. 全字母句 (Pangram) 这个概念本身就是一个知识点啦。它指包含了字母表中所有字母的句子。除了题目里的例子,还有一个很经典的 "Sphinx of black quartz, judge my vow." 也是哦。

  2. 大小写转换 std::tolower() 在处理英文字符串时,经常会遇到需要忽略大小写的情况。C++ 的 <cctype> 头文件里提供了 std::tolower()std::toupper() 两个函数,分别可以把一个字符转成小写和大写。超级方便的,对吧?

  3. 使用布尔数组进行标记 用一个布尔数组来记录一组成员(比如26个字母)是否存在,是一种非常常见且高效的技巧。它本质上是一种最简单的哈希表(或者叫位图),数组的索引直接对应我们要检查的元素。因为索引计算非常快 (char - 'a'),所以这个方法效率很高。

  4. 另一种思路:使用集合 std::set 除了用布尔数组,我们还可以用 C++ 的 std::set 容器来解决这个问题。set 是一个会自动排序且不允许重复元素的集合。

    • 我们可以遍历输入字符串。
    • 把每个字符都转成小写,然后插入到 set 中。
    • 因为 set 会自动处理重复,所以不管一个字母出现多少次,最终在 set 里只会有一个。
    • 遍历结束后,我们只需要检查一下 set 的大小(set.size())。如果大小等于26,就说明所有字母都出现过,是全字母句!这种方法代码写起来可能更简洁一些,也是很棒的思路呢。

好啦,这次的题解就到这里啦!是不是很简单很有趣呢?主人下次遇到类似的题目,一定也能轻松解决的,喵~!

Released under the MIT License.