题解:学而思编程 数数字

【题目来源】

学而思编程:数数字

【题目描述】

给定 \(n\) 个正整数\(a_1,a_2,\dots,a_n\),请你找出这些正整数中一共有多少个互不相同的正整数。

例如:\(3\)\(1\)\(2\)\(1\)\(5\) 中一共有 \(4\) 个互不相同的正整数,分别是 \(1\)\(2\)\(3\)\(5\)

【输入】

第一行一个整数 \(n\)

第二行 \(n\) 个正整数 \(a_1,a_2,\dots,a_n\)

【输出】

一行一个整数,表示互不相同的正整数的数量。

【输入样例】

3
1 2 3

【输出样例】

3

【核心思想】

  1. 问题分析:给定 \(n\) 个正整数,统计其中互不相同的正整数个数。这是一个频次统计 + 去重计数问题,关键在于记录每个数字是否出现过,然后统计出现过的数字种类数。

  2. 算法选择

    • 计数数组box[x] 记录数字 \(x\) 出现的次数
    • 线性扫描去重:遍历值域,统计出现次数大于 \(0\) 的数字个数
  3. 关键步骤

    • 初始化:读取 \(n\)
    • 统计频次
      • 遍历 \(i\)\(1\)\(n\)
        • 读取 \(x\)
        • box[x]++:标记数字 \(x\) 出现
    • 统计不同数字个数
      • cnt = 0
      • 遍历 \(i\)\(1\)\(10^6\)(值域):
        • box[i] > 0cnt++(该数字出现过)
    • 输出 cnt
  4. 时间/空间复杂度

    • 时间复杂度:\(O(n + V)\)\(V\) 为值域大小(\(10^6\)),输入统计 \(O(n)\),扫描值域 \(O(V)\)
    • 空间复杂度:\(O(V)\),计数数组 box[1..V]
  5. 计数数组的核心思想

    • 值域有限性:题目隐含值域不大(\(1 \leq a_i \leq 10^6\)),可用数组直接映射
    • 出现即标记:无需关心具体次数,只需知道是否出现过(> 0),但计数数组同时支持更复杂的频次查询
    • 线性扫描值域:遍历固定值域统计非零位置,得到不同数字的种类数
    • 替代方案:若值域大或未知,可用 setsort + unique,但计数数组在值域适中时效率最高
    • 适用于"有限值域内去重计数"类问题,计数数组实现简单、查询高效

【解题思路】

【算法标签】

模拟

【代码详解】

#include <bits/stdc++.h>
using namespace std;
const int N = 1e6;  // 数组大小
int n, x, box[N + 10];  // n: 数字个数, x: 临时变量, box: 计数数组
int main()
{
    cin >> n;  // 输入数字个数
    for (int i = 1; i <= n; i++)  // 输入n个数字
    {
        cin >> x;
        box[x]++;  // 统计每个数字出现的次数
    }
    int cnt = 0;  // 不同数字的个数
    for (int i = 1; i <= 1e6; i++)  // 遍历所有可能的值
    {
        if (box[i] > 0)  // 如果这个数字出现过
        {
            cnt++;  // 计数器加1
        }
    }
    cout << cnt << endl;  // 输出不同数字的个数
    return 0;
}

【运行结果】

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