数组中的最长连续子序列
题目描述:
给定无序数组arr,返回其中最长的连续序列的长度(要求值连续,位置可以不连续,例如 3,4,5,6为连续的自然数)
输入描述:
输出两行,第一行包括一个整数 n ( 1 ≤ n ≤ 1 0 5 ) n(1 \leq n \leq10^5) n(1≤n≤105),第二行包含n个整数,分别代表 a r r [ i ] ( 1 ≤ a r r [ i ] ≤ 1 0 8 ) arr[i](1 \leq arr[i] \leq 10^8 ) arr[i](1≤arr[i]≤108) 。
输出描述:
输出一个整数,代表最长连续子序列的长度。
示例1
输入
6
100 4 200 1 3 2
输出
4
示例2
输入
3
1 1 1
输出
1
备注:
时间复杂度 O ( n l o g 2 n ) O(nlog_2n) O(nlog2n),空间复杂度 O ( n ) O(n) O(n)。
题解:
解法一:
直接对数组进行排序,连续的数字必然挨在一块,逐个遍历一遍即可。
时间复杂度: O ( n ) O(n) O(n)
额外空间复杂度: O ( 1 ) O(1) O(1)
解法一代码:
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 1e5 + 10;
int n;
int a[N];
int main(void) {
scanf("%d", &n);
for (int i = 0; i < n; ++i) scanf("%d", a + i);
sort(a, a + n);
int max_len = 1, len = 1;
for (int i = 1; i < n; ++i) {
if (a[i] == a[i - 1] + 1) ++len;
else if (a[i] == a[i - 1]) continue;
else {
max_len = max(max_len, len);
len = 1;
}
}
printf("%d\n", max(max_len, len));
return 0;
}
解法二:
使用哈希表,hash<key, val> 表示 key 所在的最长连续序列的长度。逐个遍历数组元素,假设当前遍历元素为 a[i],并且 a[i] 未在 hash 中出现,则按照以下规则更新:
-
若 a[i] - 1 在 hash 中出现,则 a[i] - 1 可以和 a[i] 进行合并,找到序列最左边的位置: l e f t = a [ i ] − 1 − h a s h [ a [ i ] − 1 ] + 1 left = a[i] - 1 - hash[a[i] - 1] + 1 left=a[i]−1−hash[a[i]−1]+1,最右边位置: r i g h t = a [ i ] + h a s h [ a [ i ] ] − 1 right = a[i] + hash[a[i]] - 1 right=a[i]+hash[a[i]]−1;
-
若 a[i] + 1 在 hash 中出现,则 a[i] + 1 可以和 a[i] 进行合并,找到序列最左边的位置:
l e f t = a [ i ] − h a s h [ a [ i ] ] + 1 left = a[i] - hash[a[i]] + 1 left=a[i]−hash[a[i]]+1,最右边位置: r i g h t = a [ i ] + 1 + h a s h [ a [ i ] + 1 ] − 1 right = a[i] + 1 + hash[a[i] + 1] - 1 right=a[i]+1+hash[a[i]+1]−1;
-
序列长度为 r i g h t − l e f t + 1 right - left + 1 right−left+1,更新最大序列长度,并在 hash 中更新 left 和 right 的状态。
时间复杂度: O ( n ) O(n) O(n)
额外空间复杂度: O ( n ) O(n) O(n)
解法二代码:
#include <cstdio>
#include <unordered_map>
using namespace std;
int n, ret = 1;
unordered_map<int, int> Hash;
void merge(int less, int more) {
int left = less - Hash[less] + 1;
int right = more + Hash[more] - 1;
int len = right - left + 1;
if (len > ret) ret = len;
Hash[left] = Hash[right] = len;
}
int main(void) {
scanf("%d", &n);
int x;
while (n--) {
scanf("%d", &x);
if (!Hash.count(x)) {
Hash[x] = 1;
if (Hash.count(x - 1)) merge(x - 1, x);
if (Hash.count(x + 1)) merge(x, x + 1);
}
}
printf("%d\n", ret);
return 0;
}