题解:学而思编程 独一无二

【题目来源】

学而思编程:独一无二

【题目描述】

X国的所有居民都具有一个共同的强迫症,那就是独特。对于任何东西他们都要尽可能保证独一无二,以至于独特成为了他们追求的完美。

他们的彩票中间规则也是十分独特,每一个买彩票的人选中一个范围在 \([1,10^4]\) 的数字,将所有数字按从小到大的顺序排成一排。数列中,只出现过一次且排位最靠前的那个数字就是中奖号码。

例如,\(7\) 个人购买了彩票,所买数字依次是\(5\) \(5\) \(17\) \(31\) \(67\) \(88\) \(88\),则第三个数字 \(17\) 为中奖号码。

【输入】

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

第二行 \(n\) 个空格隔开的整数表示彩票数字。

【输出】

一行一个整数,如果没有人中奖,则输出 \(-1\),反之输出中奖号码。

【输入样例】

7
5 5 17 31 67 88 88

【输出样例】

17

【核心思想】

  1. 问题分析:给定 \(n\)\([1, 10^4]\) 范围内的整数,找出只出现过一次且数值最小的那个数。这是一个频次统计 + 最小值查找问题,关键在于先统计每个数字的出现次数,再按数值从小到大找到第一个出现次数为 \(1\) 的数。

  2. 算法选择

    • 计数数组num[x] 记录数字 \(x\) 出现的次数
    • 线性扫描找最小:遍历值域 \(1\)\(100000\),第一个 num[i] == 1\(i\) 即为答案
  3. 关键步骤

    • 初始化:读取 \(n\)
    • 统计频次
      • 遍历 \(i\)\(1\)\(n\)
        • 读取 \(x\)
        • num[x]++
    • 查找中奖号码
      • 遍历 \(i\)\(1\)\(100000\)
        • num[i] == 1:返回 \(i\)(第一个只出现一次的数,即数值最小且排位最靠前)
      • 若遍历结束未找到:返回 \(-1\)
    • 输出结果
  4. 时间/空间复杂度

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

    • 频次统计:通过数组下标直接映射数字,\(O(1)\) 记录每次出现
    • 最小值优先:按数值从小到大扫描,第一个满足条件的即为"排位最靠前"的,符合题目要求
    • 值域利用:题目限定值域 \([1, 10^4]\),数组大小开到 \(10^5\) 足够,实现简单高效
    • 无解处理:遍历完值域仍未找到 num[i] == 1,说明所有数都重复或没有数,返回 \(-1\)
    • 适用于"有限值域 + 频次约束 + 最小值查找"类问题,计数数组配合顺序扫描是标准解法

【算法标签】

模拟

【代码详解】

#include <bits/stdc++.h>
using namespace std;
#define int long long
int n, num[100010], x;  // n: 数字个数, num: 计数数组, x: 临时变量

int work()
{
    for (int i = 1; i <= 100000; i++)  // 遍历1到100000
    {
        if (num[i] == 1)  // 如果数字i只出现一次
        {
            return i;  // 返回这个数字
        }
    }
    return -1;  // 没有找到只出现一次的数字
}
signed main()
{
    cin >> n;  // 输入数字个数
    for (int i = 1; i <= n; i++)  // 输入n个数字
    {
        cin >> x;
        num[x]++;  // 统计数字x出现的次数
    }
    cout << work() << endl;  // 输出结果
    return 0;
}

【运行结果】

7
5 5 17 31 67 88 88
17
posted @ 2026-07-05 14:38  团爸讲算法  阅读(5)  评论(0)    收藏  举报