LeetCode Top 100 Liked Questions 128. Longest Consecutive Sequence (Java版; Hard)

独自空忆成欢 提交于 2019-11-30 05:46:05

welcome to my blog

LeetCode Top 100 Liked Questions 128. Longest Consecutive Sequence (Java版; Hard)

题目描述

Given an unsorted array of integers, find the length of the longest consecutive elements sequence.

Your algorithm should run in O(n) complexity.

Example:

Input: [100, 4, 200, 1, 3, 2]
Output: 4
Explanation: The longest consecutive elements sequence is [1, 2, 3, 4]. Therefore its length is 4.

第一次做; 使用哈希表, 将暴力解法变成了时间复杂度为O(n)的最优解;使用哈希表并没有增加复杂度, 因为使用哈希表进行增删改查, 可以认为时间复杂度是O(1); 使用有序表(红黑树,AVL树,SB树,跳表)的大部分操作()都是O(logn)的, 少数是O(1)的; 理解如何去找子序列的下界; 理解为什么每个元素最多被访问两次

/*
暴力法之所以费时间是因为每个元素都可能被访问多次, 实际上我们在找子序列时, 希望从子序列的开头开始遍历, 那么如何找到子序列的开头呢?
可以借助哈希表, 记录数组中的所有元素, 遍历每一个元素时, 如果哈希表中包含nums[i]-1这个元素, 说明nums[i]不是子序列的开头,也就是说,
子序列的开头是这样的元素: a在哈希表中, 但是a-1不在哈希表中
找到了子序列的开头元素,接着开始使用while循环找上界; 
虽然存在循环嵌套, 但是数组中每个元素最多访问两次: 第一次是检查是否可以作为子序列的开头; 第二次是寻找某个子序列的上界时可能会被访问
核心:
1. 理解如何找子序列的下界
2. 理解为什么数组中每个元素最多访问两次

脑子别僵了, O(n)的时间复杂度不是说只遍历一遍数组, 可以遍历多次数组的
*/
import java.util.Set;
import java.util.HashSet;

class Solution {
    public int longestConsecutive(int[] nums) {
        //input check
        if(nums==null || nums.length==0)
            return 0;
        Set<Integer> hs = new HashSet<>();
        for(int num : nums)
            hs.add(num);//这样是不是会自动处理重复值
        int currLen = 1, maxLen = 1, a;
        for(Integer num : hs){
            //找子序列的下界
            if(!hs.contains(num-1)){
                a = num;
                currLen = 1;
                //内循环会使得某些元素被访问两次
                while(hs.contains(a+1)){
                    currLen++;
                    a++;
                }
                maxLen = Math.max(maxLen, currLen);
            }
        }
        return maxLen;
    }
}

第一次做; 时间复杂度取决于排序算法, O(nlogn); 理解maxLen和currLen的初始化; 配合案例[1,2,0,1]理解如何处理nums[i]==nums[i-1]的情况

/*
先来个O(nlogn)的算法
先排序,再从头开始遍历
绊脚案例:
[1,2,0,1]   3
*/
import java.util.Arrays;

class Solution {
    public int longestConsecutive(int[] nums) {
        if(nums==null || nums.length==0)
            return 0;
        Arrays.sort(nums);
        //因为input check后数组中至少有一个元素, 所以将maxLen和currLen初始化为1
        int maxLen = 1, currLen = 1;
        //当前元素和前一个元素比较
        for(int i=1; i<nums.length; i++){
            if(nums[i]==nums[i-1]){
                //想起楚为什么nums[i]==nums[i-1]时不需要将currLen置1, 案例提示:[1,2,0,1]   3
                continue;
            }
            if(nums[i]==nums[i-1] + 1){
                currLen++;
                maxLen = Math.max(maxLen, currLen);
            }
            else{                
                currLen=1;
            }
        }
        return maxLen;
    }
}

题解, 暴力解法; 理解O(n^3)是怎么来的; 注意for循环和while循环的写法

  • 遍历每一个数, O(n)
  • 对于每一个数a, 判断a+1是否在数组中, O(n)
  • 输入是[1,2,3,4,5]时, 对于1, 需要判断2是否在数组中, 3是否在数组中,…5是否在数组中, 6是否在数组中, 需要判断O(n)次
  • 上面三步整合在一起就是O(n^3)
class Solution {
    public int longestConsecutive(int[] nums) {
        int longestStreak = 0;
        for (int num : nums) {
            int currentNum = num;
            int currentStreak = 1;

            while (arrayContains(nums, currentNum + 1)) {
                currentNum += 1;
                currentStreak += 1;
            }

            longestStreak = Math.max(longestStreak, currentStreak);
        }

        return longestStreak;
    }
    
    private boolean arrayContains(int[] arr, int num) {
        for (int i = 0; i < arr.length; i++) {
            if (arr[i] == num) {
                return true;
            }
        }
        return false;
    }
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!