题目大意:
最长连续序列
给定一个未排序的整数数组,找出最长连续序列的长度。
要求算法的时间复杂度为 O(n)。
示例:
输入: [100, 4, 200, 1, 3, 2]
输出: 4
解释: 最长连续序列是 [1, 2, 3, 4]。它的长度为 4。
如果想查看本题目是哪家公司的面试题,请参考以下免费链接: https://leetcode.jp/problemdetail.php?id=128
解题思路分析:
这道题的本质是要给数字分组,只要是相差为1的数字都要被分到一个组,需要注意的是每组数据中不能有重复的数字。解决分组问题的最好办法是使用Union-Find并查集,解题步骤大致如下:
- 先建立一个root数组,表示每个数字的组号(根节点下标),初始时,每个数字自己一组,即root[i]=i。
- 建立一个map,循环每一个数字,利用map记录已经出现过的数字,key为数字,value为该数字的下标。如果当前数字在map中存在,说明该数字为重复数字,可以跳过。然后查看该数字加一的值是否在map中存在过,如果存在,则将该数字与当前数字做Union操作(将一个数字的根节点连接到另一个数字的根节点上,使得2个数字的根节点相同,即表示为同一组),同理如果map中存在当前数字减一,也将这两个数字进行Union操作。
- 最后循环一遍root数组,查看每个数字的根,统计相同根的个数最多的即是返回结果。
实现代码:
int[] root; // 分组用的数组 public int longestConsecutive(int[] nums) { // 初始化root数组 root = new int[nums.length]; // 初始化时,每个数字自己一组 for(int i=0;i<nums.length;i++) root[i]=i; // 记录出现过的数字 Map<Integer,Integer> map = new HashMap(); // 循环每个数字 for(int i=0;i<nums.length;i++){ // 当前数字 int n=nums[i]; // 如果当前数字在map中存在,说明是重复数字,跳过 if(map.containsKey(n)) continue; // 如果map中存在当前数字减一,Union该数字与当前数字 if(map.containsKey(n-1)) union(i, map.get(n-1)); // 如果map中存在当前数字加一,Union该数字与当前数字 if(map.containsKey(n+1)) union(i, map.get(n+1)); // 将当前数字与下标存入map map.put(n,i); } // 返回结果 int res=0; // 统计同根的数字个数 int[] count = new int[nums.length]; for(int i=0;i<nums.length;i++){ // 找到当前数字的根 int root=root(i); // 当前根下的数字加一,同时更新返回结果最大值 res=Math.max(res, ++count[root]); } return res; } // 查找根(Find) int root(int index){ // 根元素的特点是下标等于值 while(index!=root[index]){ index=root[index]; } return index; } // 合并两个数字下标 void union(int index1, int index2){ // 将index2的根连接到index1的根下 root[root(index1)] = root(index2); }
本题解法执行时间为7ms。
Runtime: 7 ms, faster than 61.06% of Java online submissions for Longest Consecutive Sequence.
Memory Usage: 36.8 MB, less than 98.28% of Java online submissions for Longest Consecutive Sequence.
本网站文章均为原创内容,并可随意转载,但请标明本文链接如有任何疑问可在文章底部留言。为了防止恶意评论,本博客现已开启留言审核功能。但是博主会在后台第一时间看到您的留言,并会在第一时间对您的留言进行回复!欢迎交流!
本文链接: https://leetcode.jp/leetcode-128-longest-consecutive-sequence-解题思路分析/