最长连续序列

核心思路,假设这个序列由若干个子序列构成,每个子序列都是连续序列,目的就是找到这些子序列的长度最大值。

由于可能存在重复元素,所以需要对原始序列进行去重。

为了统计每个子序列的长度,我们可以取每个子序列的最小值,一直往上找它的下一个值是否在原序列中,如果存在,那么子序列长度 + 1。

最后对所有子序列的长度取一个最大值就是最终答案。

Java 解法

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class Solution {
    public int longestConsecutive(int[] nums) {
        if (nums.length == 0 ) {
            return 0;
        }
        Set<Integer> set = new HashSet<>();
        for (Integer num : nums) {
            set.add(num);
        }

        int res = 1;
        for (Integer num : set) {
            if (set.contains(num-1)) {
                continue;
            }
            int cur = 1;
            int t = num + 1;
            while(set.contains(t)) {
                cur ++;
                if (cur > res) {
                    res = cur;
                }
                t ++;
            }
        }
        return res;
    }
}

其实上面的代码可以简化一点, cur 可以用 y-x 提替代

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
import java.util.HashSet;
import java.util.Set;

class Solution {
    public int longestConsecutive(int[] nums) {
        Set<Integer> set = new HashSet<>(nums.length * 2);

        for (int x : nums) set.add(x);

        int ans = 0;
        for (int x : set) {
            // 只从“连续序列的起点”开始扩展,避免重复扫描,保证整体 O(n)
            if (!set.contains(x - 1)) {
                int y = x;
                while (set.contains(y)) y++;
                ans = Math.max(ans, y - x);
            }
        }
        return ans;
    }
}

python 解法

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
class Solution:
    def longestConsecutive(self, nums: List[int]) -> int:
        s = set(nums)
        ans = 0

        for x in s:
            if x - 1 not in s:
                y = x
                while y in s:
                    y += 1
                ans = max(ans, y-x)

        return ans

python set 用法:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# 初始化
s = set()                    # 空集合(注意:{} 是空 dict)
s = {1, 2, 3}                # 字面量创建
s = set([1, 2, 2, 3])        # 去重 -> {1, 2, 3}
s = set("abca")              # {'a','b','c'}

# 增加元素
s.add(10)                    # 加单个元素
s.update([1, 2, 3])           # 批量加入(可迭代对象)

# 删除元素
s.remove(10)                 # 不存在会抛 KeyError
s.discard(10)                # 不存在不报错(更稳)
v = s.pop()                  # 随机弹出一个元素(集合无序)
s.clear()                    # 清空

# 查询元素
10 in s                      # 成员测试(平均 O(1))
len(s)                       # 元素个数

# 集合运算
# 并集
a | b
a.union(b)

# 交集
a & b
a.intersection(b)

# 查集
a - b
a.difference(b)

Go 解法

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
func longestConsecutive(nums []int) int {
	set := make(map[int]struct{}, len(nums))
	for _, x := range nums {
		set[x] = struct{}{}
	}

	ans := 0
	for x := range set {
		// 只从“序列起点”开始扩展,保证整体 O(n)
		if _, ok := set[x-1]; ok {
			continue
		}
		y := x
		for {
			if _, ok := set[y]; !ok {
				break
			}
			y++
		}
		if y-x > ans {
			ans = y - x
		}
	}
	return ans
}

go 语言中,需要注意的就是没有 set 这一个数据结构,只有 map。

JS 解法

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/**
 * LeetCode 128 - Longest Consecutive Sequence
 * 时间复杂度:O(n) 平均
 * 空间复杂度:O(n)
 *
 * @param {number[]} nums
 * @return {number}
 */
function longestConsecutive(nums) {
  const set = new Set(nums);
  let ans = 0;

  for (const x of set) {
    // 只从“连续序列的起点”开始扩展,避免重复扫描
    if (set.has(x - 1)) continue;

    let y = x;
    while (set.has(y)) y++;
    ans = Math.max(ans, y - x);
  }

  return ans;
}