算法学习(一)

题目】求数组中的最长连续序列的长度,序列中每个值的索引不要求连续,但值时连续的。
例如】数组data={9, 1, 8, 3, 2, 4},最长连续序列为{1, 2, 3, 4},返回4。
所属范围】动态规划
】本题使用一个HashMap存储中间状态,key为数组元素值,value为该值所在的连续序列的长度。遍历数组时,利用HashMap可以判断当前元素 data[i] 是否已经出现过,如果出现过了,就不作处理,因为它不会影响已有的连续序列的发生扩张。如果没有出现过,就把它当做是长度为1的连续序列加入到map中。

接下来,我们判断 data[i]-1 在不在map中,如果在的话,说明可以合并 data[i]-1 所在的序列和 data[i] 所在的序列。由于 data[i] 是第一次出现,所以data[i]-1所在的连续序列必然不包含 data[i],那么 data[i]-1 所在的序列必然是从 data[i]-1 开始向左延伸的,现在我们可以找到 data[i]-1 所在连续序列的最左位置记为left。同样的道理,data[i] 所在的子序列必然是从 data[i] 开始向右延伸,所以可以找到该序列的最右位置记为right,现在 data[i-1]和 data[i] 将两个子序列连接起来了,合并后的连续序列的最左端为left,最右端为right,合并后的序列长度为 right-left+1,然后更新 left 和 right 在map中的value,也就是它们所在连续序列的长度。由于 left 和 right 之间的值不会影响该连续序列的扩张,因此,不需要更新它们在map中的value,只用作是否存在过的依据。

同理,对于data[i]和data[i+1]也可以按照上述方式进行合并序列。

在计算序列长度的时候,我们可以更新最大长度。最后返回这个最大长度。

代码

public int longestConsecutive(int[] data){
    if(data == null || data.length == 0){
        return 0;
    }

    //使用hash表,key存储了当前的元素,value存储了当前元素所在的连续序列的长度
    Map<Integer,Integer> map = new HashMap<>();
    int max = 1;
    for(int i = 0; i < data.length; ++i){
        //已经出现过的元素不再处理
        if(!map.containsKey(data[i])){
            //首先将它作为一个长度为1的连续序列,加入到map中
            map.put(data[i],1);
            //然后看data[i]-1是否在map中
            if(map.containsKey(data[i]-1)){
                //如果在map中,表示data[i]-1所在的连续序列可以和data[i]合并,并返回合并后的连续序列的长度
                //并且,由于data[i]没有出现过,所以data[i]-1所在连续序列中不包含data[i],data[i]-1所在序列是从右向左延伸的
                max = Math.max(max,merge(map,data[i]-1,data[i]));
            }
            //data[i]+1的处理也是类似
            if(map.containsKey(data[i]+1)){
                max = Math.max(max,merge(map,data[i],data[i]+1));
            }
        }
    }
    return max;
}

private int merge(Map<Integer,Integer> map, int less, int more){
    //由于less所在的连续序列中肯定不包含more,所有可以计算得到它连续序列的起始位置
    int left = less - map.get(less) + 1;
    //more所在的连续序列也不会包含less
    int right = more + map.get(more) - 1;
    int length = right - left + 1;
    //将连续序列的首尾各自加入到map中,也就是说map中只会更新一段连续序列的首和尾,
    //如果遇到某个数把两个序列连接起来了,那么首和尾的value值都会被更新
    map.put(left,length);
    map.put(right,length);
    return length;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值