[LeetCode] 128. Longest Consecutive Sequence 求最长连续序列

本文介绍了一种算法,用于寻找非排序整数数组中最长连续序列的长度,并提供了多种编程语言的实现方法,如Java和Python等,确保了时间复杂度为O(n)。

Given an unsorted array of integers, find the length of the longest consecutive elements sequence.

For example,
Given [100, 4, 200, 1, 3, 2],
The longest consecutive elements sequence is [1, 2, 3, 4]. Return its length: 4.

Your algorithm should run in O(n) complexity.

给一个非排序的整数数组,找出最长连续序列的长度。要求时间复杂度:O(n)。

解法1:要O(n)复杂度,排序显然不行,要用hash table。将序列中的所有数存到一个unordered_set中。对于序列里任意一个数A[i],可以通过set马上能知道A[i]+1和A[i]-1是否也在序列中。如果在,继续找A[i]+2和A[i]-2,以此类推,直到将整个连续序列找到。为了避免在扫描到A[i]-1时再次重复搜索该序列,在从每次搜索的同时将搜索到的数从set中删除。直到set中为空时,所有连续序列搜索结束。

解法2: 参考自:StefanPochmann

First turn the input into a set of numbers. That takes O(n) and then we can ask in O(1) whether we have a certain number.Then go through the numbers. If the number x is the start of a streak (i.e., x-1 is not in the set), then test y = x+1, x+2, x+3, ... and stop at the first number y not in the set. The length of the streak is then simply y-x and we update our global best with that. Since we check each streak only once, this is overall O(n). This ran in 44 ms on the OJ, one of the fastest Python submissions.

 

其它参考:GeeksforGeeks

1) Create an empty hash.
2) Insert all array elements to hash.
3) Do following for every element arr[i]
  a) Check if this element is the starting point of a subsequence. To check this, we simply look forarr[i] - 1 in hash, if not found, then this is the first element a subsequence.
If this element is a first element, then count number of elements in the consecutive starting with this element.

If count is more than current res, then update res.

 

Java:

class Solution {
    public static int longestConsecutive(int[] num) {
      // if array is empty, return 0
      if (num.length == 0) {
        return 0;
      }

      Set<Integer> set = new HashSet<Integer>();
      int max = 1;

      for (int e : num)
        set.add(e);

      for (int e : num) {
        int left = e - 1;
        int right = e + 1;
        int count = 1;

        while (set.contains(left)) {
          count++;
          set.remove(left);
          left--;
        }

        while (set.contains(right)) {
          count++;
          set.remove(right);
          right++;
        }

        max = Math.max(count, max);
      }

      return max;
    }
}  

Java:

public int longestConsecutive(int[] num) {
    int res = 0;
    HashMap<Integer, Integer> map = new HashMap<Integer, Integer>();
    for (int n : num) {
        if (!map.containsKey(n)) {
            int left = (map.containsKey(n - 1)) ? map.get(n - 1) : 0;
            int right = (map.containsKey(n + 1)) ? map.get(n + 1) : 0;
            // sum: length of the sequence n is in
            int sum = left + right + 1;
            map.put(n, sum);
            
            // keep track of the max length 
            res = Math.max(res, sum);
            
            // extend the length to the boundary(s)
            // of the sequence
            // will do nothing if n has no neighbors
            map.put(n - left, sum);
            map.put(n + right, sum);
        }
        else {
            // duplicates
            continue;
        }
    }
    return res;
}  

Java:

public int longestConsecutive(int[] nums) {
        Map<Integer,Integer> ranges = new HashMap<>();
        int max = 0;
        for (int num : nums) {
            if (ranges.containsKey(num)) continue;
            
            // 1.Find left and right num
            int left = ranges.getOrDefault(num - 1, 0);
            int right = ranges.getOrDefault(num + 1, 0);
            int sum = left + right + 1;
            max = Math.max(max, sum);
            
            // 2.Union by only updating boundary
            // Leave middle k-v dirty to avoid cascading update
            if (left > 0) ranges.put(num - left, sum);
            if (right > 0) ranges.put(num + right, sum);
            ranges.put(num, sum); // Keep each number in Map to de-duplicate
        }
        return max;
    } 

Java: 2

public int longestConsecutive(int[] nums) {
            Set<Integer> set = new HashSet<>();
            for(int n : nums) {
                set.add(n);
            }
            int best = 0;
            for(int n : set) {
                if(!set.contains(n - 1)) {  // only check for one direction
                    int m = n + 1;
                    while(set.contains(m)) {
                        m++;
                    }
                    best = Math.max(best, m - n);
                }
            }
            return best;
        }  

Python:

class Solution:
    # @param num, a list of integer
    # @return an integer
    def longestConsecutive(self, num):
        result, lengths = 1, {key: 0 for key in num}
        for i in num:
            if lengths[i] == 0:
                lengths[i] = 1
                left, right = lengths.get(i - 1, 0), lengths.get(i + 1, 0)
                length = 1 + left + right
                result, lengths[i - left], lengths[i + right] = max(result, length), length, length
        return result

Python: 2

def longestConsecutive(self, nums):
    nums = set(nums)
    best = 0
    for x in nums:
        if x - 1 not in nums:
            y = x + 1
            while y in nums:
                y += 1
            best = max(best, y - x)
    return best  

C++:

class Solution {
public:
    int longestConsecutive(vector<int> &num) {
        if(num.empty()) return 0;
        unordered_set<int> ht;
        for(int i=0; i<num.size(); i++)
            ht.insert(num[i]);
            
        int maxLen = 1;
        for(int i=0; i<num.size(); i++) {
            if(ht.empty()) break;
            int curLen = 0;
            int curNum = num[i];
            
            while(ht.count(curNum)) {
                ht.erase(curNum);
                curLen++;
                curNum++;
            }
            
            curNum = num[i]-1;
            while(ht.count(curNum)) {
                ht.erase(curNum);
                curLen++;
                curNum--;
            }
            
            maxLen = max(maxLen, curLen);
        }
        
        return maxLen;
    }
};

 

类似题目:

[LeetCode] 298. Binary Tree Longest Consecutive Sequence 二叉树最长连续序列

 

All LeetCode Questions List 题目汇总

 

转载于:https://www.cnblogs.com/lightwindy/p/8692363.html

### LeetCode128Python 解法 对于LeetCode128题——最长连续序列(Longest Consecutive Sequence),一种有效的解决方案是利用哈希表来实现。这种方法的时间复杂度为O(n)[^5]。 算法的主要思路是在遍历数组的同时,使用集合(set)存储所有的数。这样可以在常量时间内判断某个数值是否存在。为了找到最长的连续序列,针对每一个数字num,在集合中寻找num+1, num+2...直到找不到为止;同时也向负方向探索num-1, num-2...停止条件同样是遇到不存在于集合中的值。但是这种双向扩展的方式存在大量冗余计算,因为如果已经从较小的那个起点开始计算过一次完整的序列,则后续再碰到这个区间内的其他点时无需再次展开搜索。 优化后的策略是从仅从未被访问过的端点出发尝试构建可能存在的最大长度链路,并标记沿途经过的所有节点防止重复处理。具体做法如下: ```python def longestConsecutive(nums): longest_streak = 0 num_set = set(nums) for num in num_set: if num - 1 not in num_set: # 只有当当前数字是潜在序列最小值的时候才进入此逻辑 current_num = num current_streak = 1 while current_num + 1 in num_set: current_num += 1 current_streak += 1 longest_streak = max(longest_streak, current_streak) return longest_streak ``` 上述代码通过只对可能是新序列起始位置的元素执行内部循环,从而大大减少了不必要的运算次数[^5]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值