返回

渐入佳境,剖析 LeetCode #128 最长连续序列的妙招!

IOS

征服连续序列难题:LeetCode #128 解密

在算法学习的殿堂中,LeetCode 犹如一座屹立的丰碑,考验着算法爱好者的智慧和韧性。其中,#128 最长连续序列问题更是跻身 Top 100 高频题之列,成为算法高手必经的磨砺之路。

问题剖析:连续序列的奥义

给你一个无序整数数组 nums,找出最长的连续正整数序列的长度。例如:

  • 对于 nums = [100, 4, 200, 1, 3, 2],最长的连续正整数序列是 [1, 2, 3],因此返回 3。
  • 对于 nums = [1, 2, 0, 1],最长的连续正整数序列是 [1, 2],因此返回 2。

解法一:哈希表的巧妙应用

哈希表是一种强大的数据结构,可以快速查找和插入元素。在这个解法中,我们将每个整数 nums[i] 作为键,其对应的连续序列长度作为值。

算法步骤:

  1. 初始化一个哈希表 map。
  2. 遍历数组 nums,对于每个元素 nums[i]:
    • 如果 map 中包含键 nums[i],则跳过该元素。
    • 否则:
      • 向前查找比 nums[i] 大的连续整数,计算长度 left。
      • 向后查找比 nums[i] 小的连续整数,计算长度 right。
      • 将 map[nums[i]] 设置为 left + right + 1。
  3. 在哈希表中查找具有最大值的键,并返回其对应的值。

解法二:并查集的优雅合并

并查集是一种高效的算法,用于管理不交叠集合的合并和查找操作。在这个解法中,我们将每个整数 nums[i] 视为一个集合的代表元素。

算法步骤:

  1. 初始化一个并查集 uf。
  2. 遍历数组 nums,对于每个元素 nums[i]:
    • 如果 uf 中不存在包含 nums[i] 的集合:
      • 创建一个新的集合,其代表元素为 nums[i]。
    • 否则:
      • 找到包含 nums[i] 的集合的代表元素 parent。
      • 如果 parent + 1 在 uf 中存在,则合并包含 nums[i] 和 parent + 1 的集合。
  3. 返回 uf 中所有集合中元素最多的集合的元素数量。

代码示例:Swift 中的优雅实现

哈希表解法:

func longestConsecutive(_ nums: [Int]) -> Int {
    var map = [Int: Int]()
    var maxLen = 0

    for num in nums {
        guard map[num] == nil else {
            continue
        }
        
        let left = map[num - 1] ?? 0
        let right = map[num + 1] ?? 0
        
        let newLen = left + right + 1
        maxLen = max(maxLen, newLen)
        
        map[num] = newLen
        map[num - left] = newLen
        map[num + right] = newLen
    }
    
    return maxLen
}

并查集解法:

class UnionFind {
    private var parent: [Int]
    private var size: [Int]

    init(_ n: Int) {
        parent = Array(repeating: 0, count: n)
        size = Array(repeating: 1, count: n)
        for i in 0..<n {
            parent[i] = i
        }
    }
    
    func find(_ x: Int) -> Int {
        if parent[x] != x {
            parent[x] = find(parent[x])
        }
        return parent[x]
    }
    
    func union(_ x: Int, _ y: Int) {
        let rootX = find(x)
        let rootY = find(y)
        if rootX != rootY {
            if size[rootX] > size[rootY] {
                parent[rootY] = rootX
                size[rootX] += size[rootY]
            } else {
                parent[rootX] = rootY
                size[rootY] += size[rootX]
            }
        }
    }
}

func longestConsecutive(_ nums: [Int]) -> Int {
    let uf = UnionFind(nums.count)
    var numToIndex = [Int: Int]()
    
    for (i, num) in nums.enumerated() {
        numToIndex[num] = i
    }
    
    for num in nums {
        if let index = numToIndex[num - 1] {
            uf.union(i, index)
        }
        
        if let index = numToIndex[num + 1] {
            uf.union(i, index)
        }
    }
    
    var maxSize = 0
    for i in 0..<nums.count {
        maxSize = max(maxSize, uf.size[uf.find(i)])
    }
    
    return maxSize
}

结语:探索算法的无穷魅力

LeetCode #128 最长连续序列问题虽看似简单,但其蕴含的算法思想却十分精妙。通过剖析哈希表解法和并查集解法,我们深入理解了如何高效地解决此类问题。在顾毅大师的指导下,我们将算法的魅力娓娓道来,力求让每一位读者都能领悟算法的真谛。

算法的世界,如同一座浩瀚的海洋,蕴藏着无限的知识与挑战。让我们扬帆启航,不断探索算法的奥秘,在算法的征途中书写新的篇章!

常见问题解答:

  1. 什么是最长连续序列?
    最长连续序列是指数组中连续的一组正整数序列,其长度最大。

  2. 哈希表解法是如何工作的?
    哈希表解法将每个整数存储为键,其对应的连续序列长度存储为值。它高效地查找和更新连续序列长度。

  3. 并查集解法是如何工作的?
    并查集解法将每个整数视为一个集合的代表元素,并合并相邻集合。通过查找集合的代表元素,我们可以获得最长连续序列的长度。

  4. 哪种解法更有效率?
    哈希表解法的时间复杂度为 O(n),而并查集解法的平均时间复杂度也为 O(n)。对于大量重复元素的数组,哈希表解法更具优势。

  5. LeetCode #128 问题在实际场景中有哪些应用?
    该问题在 DNA 测序、数据挖掘和网络分析等领域有广泛应用。