剑指 Offer II 119. 最长连续序列(中等 图 并查集 bfs)

剑指 Offer II 119. 最长连续序列

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

示例 1:

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

输入:nums = [0,3,7,2,5,8,4,6,0,1]
输出:9

提示:

0 <= nums.length <= 104
-109 <= nums[i] <= 109

进阶:可以设计并实现时间复杂度为 O(n) 的解决方案吗?

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/WhsWhI
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

分析

方法一:图搜索
把相邻的节点构成的图看作一个岛屿,问题变为求岛屿的最大面积,用一个哈希表存储所有节点,对于每个节点用 bfs 查找其所有邻接点,记录所有相连的节点数目,同时删除哈希表中使用过的节点,因为要删除哈希表的节点,所以使用迭代器进行遍历,遍历所有哈希表中的节点找到最大的岛屿。
方法二:并查集
(用并查集没有直接图搜索快)
并查集要对找到的邻接点用 union 连接,每次连接的节点都是之前的子集,有各自的大小,需要动态保存子集大小的和,考虑使用哈希表 counts 来保存节点和其所在岛屿的大小,用哈希表 fathers 存储所有节点和其根节点,fathers 也可以用哈希表数组,但是范围太大,所以这里使用哈希表,初始化所有哈希表,counts 的 key 保存所有节点,value 保存岛屿大小起始为 1,fathers 的 key 保存所有节点,value 保存根节点起始为 key 的值。接下来进行节点的连接,findFather 和 unoin 的代码跟之前非常类似,只是参数换成了哈希表。最后遍历 counts 找出岛屿的最大面积。

题解(Java)

方法一:图搜索

class Solution {
    public int longestConsecutive(int[] nums) {
        Set<Integer> set = new HashSet<>();
        for (int num : nums) {
            set.add(num);
        }

        int longest = 0;
        while (!set.isEmpty()) {
            Iterator<Integer> it = set.iterator();
            longest = Math.max(longest, bfs(set, it.next()));
        }

        return longest;
    }

    private int bfs(Set<Integer> set, int num) {
        Queue<Integer> q = new LinkedList<>();
        q.offer(num);
        set.remove(num);
        int length = 1;
        while (!q.isEmpty()) {
            int i = q.poll();
            int[] neighbors = new int[]{i - 1, i + 1};
            for (int neighbor : neighbors) {
                if (set.contains(neighbor)) {
                    q.offer(neighbor);
                    set.remove(neighbor);
                    length++;
                }
            }
        }

        return length;
    }
}

方法二:并查集

class Solution {
    public int longestConsecutive(int[] nums) {
        Map<Integer, Integer> fathers = new HashMap<>();
        Map<Integer, Integer> counts = new HashMap<>();
        for (int num : nums) {
            fathers.put(num, num);
            counts.put(num, 1);
        }

        for (int num : nums) {
            if (fathers.containsKey(num + 1)) {
                union(fathers, counts, num, num + 1);
            }
            if (fathers.containsKey(num - 1)) {
                union(fathers, counts, num, num - 1);
            }
        }

        int longest = 0;
        for (int length : counts.values()) {
            longest = Math.max(longest, length);
        }

        return longest;
    }

    private int findFather(Map<Integer, Integer> fathers, int i) {
        if (fathers.get(i) != i) {
            fathers.put(i, findFather(fathers, fathers.get(i)));
        }

        return fathers.get(i);
    }

    private void union(Map<Integer, Integer> fathers, Map<Integer, Integer> counts, int i, int j) {
        int fatherOfI = findFather(fathers, i);
        int fatherOfJ = findFather(fathers, j);
        if (fatherOfI != fatherOfJ) {
            fathers.put(fatherOfI, fatherOfJ);

            int countOfI = counts.get(fatherOfI);
            int countOfJ = counts.get(fatherOfJ);
            counts.put(fatherOfJ, countOfI + countOfJ);
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值