top1编程
← 返回题目
题解

小玉的字符

1 条题解

  • 0
    @ 2026-8-6 0:54:22

    P4654 小玉的字符(入门)

    解题思路

    第一步,读懂题目。 小玉看到一串由小写字母组成的字符,想知道一共有多少种不同的字符,还要把不同的字符按 ASCII 码从小到大排好输出。

    第二步,用标记数组去重。 开一个标记数组 marked,marked[c] 为 true 就表示字符 c 出现过。扫描一遍字符串,把每个出现过的字符都打上标记;同一个字符第二次出现时,标记已经存在,自然就不会被重复计算了。

    第三步,利用 ASCII 码顺序免排序。 因为字符只可能是 a 到 z,而 ASCII 码中 a<b<c<...<z,字母的顺序就是从小到大的顺序。所以只要从 'a' 开始按字母顺序检查到 'z',凡是 marked[c] 为 true 就输出,输出结果天然就是从小到大排好序的,连排序都不用单独写。一边检查一边数出不同字符的个数 distinctCnt。

    第四步,用样例验证。 拿样例 "tctm" 来说:出现的字符有 t、c、m 三种,去掉重复后按顺序是 c、m、t,所以第一行输出 3,第二行输出 cmt。注意题目数据的第二行是这些字符连着写的,中间没有空格,和题面描述的"用空格隔开"不一样,要以实际测试数据为准。

    第五步,处理空输入。 和统计字符那题一样,如果输入是空串,什么都不输出。

    第六步,体会"桶排序"思想。 其实这道题不需要真正写出复杂的排序代码,因为 a 到 z 的 ASCII 码本来就是从小到大排列的,我们只要按顺序扫描一遍、遇到出现过的字符就输出,就自动完成了排序,这就是"桶排序"思想的简单应用。如果字符串里出现的是其他字符,处理方式类似,但本题限定只有小写字母,问题被大大简化了,思路也更容易讲清楚。

    参考代码

    // P4654 小玉的字符:去掉重复字符后按 ASCII 码从小到大排序输出
    #include <iostream>
    using namespace std;
    
    char str[1005] = "";
    bool marked[128];
    
    int main() {
        if (!(cin >> str)) return 0; // 输入为空时直接结束,不输出任何内容
        // 标记哪些字符出现过
        for (int i = 0; str[i] != '\0'; i++) marked[(int)str[i]] = true;
        // 统计不同字符个数,并按照 ASCII 顺序输出(数据中字符之间没有空格)
        int distinctCnt = 0;
        for (int c = 'a'; c <= 'z'; c++)
            if (marked[c]) distinctCnt++;
        cout << distinctCnt << endl;
        for (int c = 'a'; c <= 'z'; c++)
            if (marked[c]) cout << (char)c;
        cout << endl;
        return 0;
    }
    

    复杂度分析

    扫描字符串一次 O(len),再从 'a' 到 'z' 检查 26 次,总时间 O(len+26),len 最大 1000。空间上只用一个标记数组 marked,O(1)。非常高效。

    • 1