题解:洛谷 P1420 最长连号
【题目来源】
洛谷:P1420 最长连号
【题目描述】
输入长度为 \(n\) 的一个正整数序列,要求输出序列中最长连号的长度。
连号指在序列中,从小到大的连续自然数。
【输入】
第一行,一个整数 \(n\)。
第二行,\(n\) 个整数 \(a_i\),之间用空格隔开。
【输出】
一个数,最长连号的个数。
【输入样例】
10
1 5 6 2 3 4 5 6 8 9
【输出样例】
5
【核心思想】
-
问题分析:给定一个长度为 \(n\) 的正整数序列,要求找出其中最长的连续子串,使得该子串内的数字是连续递增的自然数(即后一个数恰好比前一个数大 1)。问题的本质是遍历序列并统计满足严格递增且差值为 1 的连续片段长度。
-
算法选择:
- 一次遍历 + 计数器:这是最直接的线性扫描算法。我们只需要维护一个变量记录当前连续递增段的长度,并在遍历过程中不断更新答案。由于只需要比较相邻两个数,时间复杂度为 \(O(n)\),空间复杂度为 \(O(1)\),是解决该问题的最优方法。
-
关键步骤:
- 读入:读取整数 \(n\) 和随后的 \(n\) 个整数。
- 初始化:设置当前连号长度
mark = 1,最大连号长度max = 1(当 \(n \ge 1\) 时,答案至少为 1)。设置pre存储上一个读入的数,初始值可设为第一个读入的数。 - 遍历:从第二个数开始,依次读入每个数
t。- 若
t == pre + 1,则当前连号长度mark加 1。 - 否则,当前连号中断,重置
mark = 1。 - 更新
max = max(max, mark)。 - 将
pre更新为t。
- 若
- 输出:输出
max。
-
时间/空间复杂度:
- 时间复杂度:\(O(n)\),其中 \(n\) 是序列长度,只需一次遍历。
- 空间复杂度:\(O(1)\),只使用了常数个变量。
-
模拟与连续判定:
- 核心逻辑:连号的定义要求两个相邻元素在数值上严格相差 1,且序列是连续的子串。因此,只需在单次遍历中检查所有相邻对,即可准确统计出所有连续段的长度。
- 边界情况:当 \(n=1\) 时,
max和mark初始化为 1 能正确处理。题目保证序列为正整数,无需处理负数或零。 - 适用场景:这类问题属于最基础的序列线性扫描问题,适用于所有需要统计满足简单相邻关系的连续子段长度的问题。
【算法标签】
入门 #模拟
【代码详解】
#include <bits/stdc++.h> // 包含标准库头文件(万能头文件)
using namespace std; // 使用标准命名空间
/**
* 主函数 - 程序入口
* @return 程序执行状态码(0表示成功)
*/
int main()
{
int n; // 定义变量:数字序列的长度
int t; // 定义变量:当前输入的数字
int pre = -1; // 定义变量:前一个数字,初始化为-1
int mark = 1; // 定义变量:当前连号的长度,初始为1
int max = 1; // 定义变量:最大连号长度,初始为1
cin >> n; // 输入数字序列的长度
// 遍历输入的数字序列
for (int i = 1; i <= n; i++)
{
cin >> t; // 输入当前数字
// 判断当前数字是否与前一个数字构成连号
if (t == pre + 1)
{
mark++; // 如果是连号,当前连号长度加1
}
else
{
mark = 1; // 如果不是连号,重置当前连号长度为1
}
// 更新最大连号长度
if (mark > max)
max = mark;
// 更新前一个数字为当前数字
pre = t;
}
cout << max; // 输出最大连号长度
return 0; // 程序正常结束
}
【运行结果】
10
1 5 6 2 3 4 5 6 8 9
4
浙公网安备 33010602011771号