递归和动态规划问题:数组中的最长连续序列

题目

  给定无序数组 arr, 返回其中最长的连续序列的长度.

举例

  arr=[100,4,200,1,3,2], 最长的连续序列为 [1,2,3,4],所以返回 4.

难度

  二星

解答

  本题利用哈希表可以实现时间复杂度为 O(N), 额外空间复杂度为 O(N) 的方法。具体实现方法如下:

  1. 生成哈希表 HashMap<Integer, Integer> map,key 代表遍历过的某个数,value 代表 key 这个数所在的最长连续序列的长度。同时 map 还可以表示 arr 中的一个数之前是否出现过。

  2. 从左到右遍历 arr, 假设遍历到 arr[i]。如果 arr[i] 之前出现过,直接遍历下一个数,只处理之前没出现过的 arr[i]。首先在 map 中加入记录(arr[i], 1), 代表目前 arr[i] 单独作为一个连续序列。然后看 map 中是否含有 arr[i] - 1,如果有,则说明 arr[i] - 1 所在的连续序列可以和 arr[i] 合并,合并后记为 A序列。利用 map 可以得到 A 序列的长度,记为 lenA,最小值记为 leftA,最大值记为 rightA,只在 map 中更新与 leftA 和 rightA 有关的记录,更新成 (leftA, lenA) 和 (rightA, lenA)。接下来看 map 中是否含有 arr[i] + 1,如果有,则说明 arr[i] + 1 所在的连续序列可以与 A 合并,合并后记为 B 序列。利用 map 可以得到 B 序列的长度为 lenB, 最小值记为 leftB,最大值记为 rightB,只在 map 中更新与 leftB 和 rightB 有关的记录,更新成 (leftB, lenB) 和 (rightB, lenB)。

  3. 遍历的过程中用全局变量 max 记录每次合并出的序列的长度最大值,最后返回 max。

  整个过程中,只是每个连续序列最小值和最大值在 map 中的记录有意义,中间数的记录不再更新,因为再也不会使用到。这是因为我们只处理之前没有出现的数,如果一个出现的数能够把某个连续区间扩大,或把某两个连续区间连在一起,毫无疑问,只需要 map 中有关这个连续区间最小值和最大值的记录。

  具体过程请参看如下代码中的 longestConsecutive 方法:

 1 import java.util.HashMap;
 2 
 3 public class Main {
 4     
 5     public static void main(String[] args) {
 6         int[] arr = {100,4,200,1,3,2};
 7         System.out.println(new Main().longestConsecutive(arr));//4
 8     }
 9     
10     public int longestConsecutive(int[] arr){
11         if(arr == null || arr.length == 0) return 0;
12         int max = 1;
13         HashMap<Integer, Integer> map = new HashMap<Integer, Integer>();
14         for(int i = 0, len = arr.length; i < len; i++){
15             if(!map.containsKey(arr[i])){
16                 map.put(arr[i], 1);
17                 if(map.containsKey(arr[i] - 1)){
18                     max = Math.max(max, merge(map, arr[i] - 1, arr[i]));
19                 }
20                 if(map.containsKey(arr[i]+1)){
21                     max = Math.max(max, merge(map, arr[i], arr[i] + 1));
22                 }
23             }
24         }
25         return max;
26     }
27     
28     public int merge(HashMap<Integer, Integer> map, int less, int more){
29         int left = less - map.get(less) + 1;
30         int right = more + map.get(more) - 1;
31         int len = right - left + 1;
32         map.put(left, len);
33         map.put(right, len);
34         return len;
35     }
36     
37 }

 

转载于:https://www.cnblogs.com/zlxyt/p/10575927.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值