力扣-hot100(最长连续序列 - Hash)

128. 最长连续序列

中等

给定一个未排序的整数数组 nums ,找出数字连续的最长序列(不要求序列元素在原数组中连续)的长度。

请你设计并实现时间复杂度为 O(n) 的算法解决此问题。

示例 1:

输入:nums = [100,4,200,1,3,2]
输出:4
解释:最长数字连续序列是 [1, 2, 3, 4]。它的长度为 4。

  • 0 <= nums.length <= 105

  • -109 <= nums[i] <= 109

第一想法,先预处理一波,可以创建一个数组把存在的数都标记一遍,如:nums = [100,4,200],标记:number[100] = 1, number[4] = 1, number[200] = 1; 然后从最小的数开始遍历到最后一个数,便可确定最大连续数了。但数据范围之大让我退去....(悲哀 为什么没看清题目再动手 白死八百个脑细胞 TOT)

解法一:

啧啧啧,要求O(n)的复杂度,每个数都只能被访问一次。那么我可以将数组中的分为 n 个组,毕竟组是相对有序的,比直接在乱七八糟的原数组里直接做要来的方便。那么要加入某个组的关键是什么?且看题目:【找出数字连续的最长序列】 有序!就是前后最近的元素只差1。一旦断了,那断的那个数你就自己做队长去招募你的队员吧。那该怎么维护一个组呢? 这里组最重要的就是连续数不能断,断了的话你就自己为队长。也就是我只要找到队长就能找到这个队伍所有的成员了。(心机之蛙一直摸你肚子 WOW) key -> 队长。众所周知,队长是开头的,前面是没有元素的。那么如果出现一样的元素怎么办?这样就可能有两个一样的元素带领同一队的元素,出现重复遍历。有没有这样一种数据结构会将重复出现的元素给打掉(如来佛祖与真假美猴王的场景正在攻击我OVO)。有的兄弟有的, Set 出来亮个相。我们只需要从队长开始不断的报数就可以统计该组的元素数量,然后求每个组的max就行了。

代码如下

class Solution {
    public int longestConsecutive(int[] nums) {
        // 去重
        Set<Integer> set = new HashSet<>();
        for(int i : nums) set.add(i);
        // 定义元素最多组的数量
        int maxSize = 0;
​
        for(int i : set){
            // 判断该元素是不是连续数开头的那个元素(队长)
            // 如果是
            if(!set.contains(i - 1)){
                int CurrentNumber = i;
                int CurrentSize = 1;
                
                // 只要能找到队员就一直找下去
                while(set.contains(CurrentNumber + 1)){
                    CurrentNumber ++;
                    CurrentSize ++;
                }
                // 结束,进行队员数量结算
                maxSize = Math.max(maxSize, CurrentSize);
            }
        }
        return maxSize;
    }
}

时间复杂度 O(n)

执行代码时间 29ms 击败85.29%

解法二:0 <= nums.length <= 105 , 那么 nlogn = 10^7 - 10^8 .只要低于10^9 过的概率还是大的。题目要求:时间复杂度为 O(n) 的算法解决此问题。不管辣 。排序完后硬做就很简单了~~~

class Solution {
    public int longestConsecutive(int[] nums) {
        int len=nums.length;
        if(len==0){
            return 0;
        }
        if(len==1){
            return 1;
        }
        Arrays.sort(nums);
        int k=1;
        int max=1;
        for(int i=1;i<len;i++){
            if(nums[i]==nums[i-1])
                    continue;
            if(nums[i]-nums[i-1]==1){
                k++;
            max=Math.max(max,k);
            }else{
                k=1;
            }
        }
        return max;
    }
}
### LeetCode 最长连续序列 Python 解法 #### 方法一:基于集合的线性时间复杂度算法 通过将输入数组转换为集合 `num_set`,可以快速判断某个数字是否存在。对于每个数字 `n`,如果其前驱 `n-1` 不在集合中,则尝试从当前数字向右扩展,直到找不到下一个连续数字为止。 以下是实现该方法的具体代码: ```python class Solution: def longestConsecutive(self, nums): num_set = set(nums) max_length = 0 for n in num_set: if n - 1 not in num_set: # 只有当不存在前驱时才开始计算 current_num = n current_streak = 1 while current_num + 1 in num_set: # 向右扩展 current_num += 1 current_streak += 1 max_length = max(max_length, current_streak) # 更新最大长度 return max_length ``` 这种方法的时间复杂度为 O(n),因为每个数字最多被访问两次(一次用于检查起点,另一次用于扩展)。空间复杂度也为 O(n)[^3]。 --- #### 方法二:动态规划与并查集优化 另一种思路是利用并查集来维护连通分量之间的关系。具体来说,可以通过查找父节点的方式合并相邻的区间,并记录每组的最大长度。 虽然此方法较为复杂,但在某些特定场景下可能更高效。以下是伪代码框架: ```python def union_find_longest_consecutive(nums): parent = {} def find(x): if parent[x] != x: parent[x] = find(parent[x]) return parent[x] def union(x, y): rootX = find(x) rootY = find(y) if rootX != rootY: parent[rootY] = rootX for num in nums: parent[num] = num if num - 1 in parent: union(num, num - 1) if num + 1 in parent: union(num, num + 1) count = collections.defaultdict(int) for num in parent.keys(): root = find(num) count[root] += 1 return max(count.values(), default=0) ``` 上述代码实现了基于并查集的方法,适合处理大规模数据集[^4]。 --- #### 测试案例分析 考虑测试用例 `[100, 4, 200, 1, 3, 2]` 的执行过程: 1. 将所有数字存入集合 `{100, 4, 200, 1, 3, 2}`。 2. 遍历集合中的每一个数字: - 对于 `100` 和 `200`,由于它们没有前驱,分别形成独立子序列 `[100]` 和 `[200]`。 - 对于 `1`,发现它可以扩展到 `[1, 2, 3, 4]`,因此更新最大长度为 4。 3. 返回最终结果 `4`。 这一逻辑完全符合题目描述的要求。 --- ### 结论 综上所述,最常用的解决方案是基于集合的操作方式,因为它简单易懂且性能优越。而并查集则适用于更加复杂的场景或者需要额外功能支持的情况。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值