数组中的最长连续子序列

数组中的最长连续子序列

题目描述:

给定无序数组arr,返回其中最长的连续序列的长度(要求值连续,位置可以不连续,例如 3,4,5,6为连续的自然数)

输入描述:

输出两行,第一行包括一个整数 n ( 1 ≤ n ≤ 1 0 5 ) n(1 \leq n \leq10^5) n(1n105),第二行包含n个整数,分别代表 a r r [ i ] ( 1 ≤ a r r [ i ] ≤ 1 0 8 ) arr[i](1 \leq arr[i] \leq 10^8 ) arr[i](1arr[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]1hash[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 rightleft+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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值