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

题目:

 

思路:

【1】既然说了是O(N),那么基本就是不能用排序了,又要O(N),那么明摆着是要循环,而由于这里可以存在重复数据,但是判断连续却又不一定用得上重复的,所以用哈希表去重,去重完,理想点就是从每个连续的开头进行遍历,那么怎么才算是开头呢,假设要从K值开始遍历,那么K-1不存在就是连续数据的开头了,所以基于这种思路,第一次循环进行去重和填进hash表中,然后用hash表进行循环(存在去重的情况则属于优化,没有去重的情况也不影响结果),然后只对K-1不存在的数据K进行遍历,防止多次递归,这样除开基础的两次循环,再加上递归的1次,一个数据最多只会出现3次遍历。

代码展示:

//时间13 ms击败75.9%
//内存56.2 MB击败53.80%
public int longestConsecutive(int[] nums) {
    // 首先为什么采用hash表,因为0 <= nums.length <= 10^5
    // 而-10^9 <= nums[i] <= 10^9,所以值远比个数的范围要大,且还有负数
    // 所以用int数组之类的就不太能够优化,也就只能使用map结构了
    Set<Integer> num_set = new HashSet<Integer>();
    // 其次set去重也能更进一步减少遍历的个数
    // 因为求得是最大连续,与该值的个数无关
    for (int num : nums) num_set.add(num);

    int longestStreak = 0;

    for (int num : num_set) {
        // 这一步的内容是
        // 如果值为3,如果存在2的话就直接跳过,因为遇到2的时候会遍历3,所以减少重复遍历的次数
        // 其目的是减少遍历的分支:如【2,3,4,5,6,7,8】,

        // 如果不加该判断8会遍历多少次:
        // 你会发现最外层本身就会遍历一遍,故8遍历次数保底是1
        // 当遇到2的时候又会循环一次,3,4,5,6,7同理, 所以8被遍历的次数为7
        // 这种就是比较恐怖的O(N^2)的时间复杂度了,随着连续数组的长度增加遍历的次数也会上升
        // O(N^2)直白一点就是 数组长度x * 连续数组长度y = xy ,由于两个都是未知的故都用N替代

        // 如果不加该判断8会遍历多少次:
        // 你会发现最外层本身就会遍历一遍,故8遍历次数保底是1
        // 当遇到2的时候又会循环一次,3,4,5,6,7则会因为都存在前一位数字而跳过, 所以8被遍历的次数为2
        // 这种就是比较恐怖的O(N)的时间复杂度了,随着连续数组的长度增加遍历的次数也只会是2
        if (!num_set.contains(num - 1)) {
            int currentNum = num;
            int currentStreak = 1;

            while (num_set.contains(currentNum + 1)) {
                currentNum += 1;
                currentStreak += 1;
            }

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

    return longestStreak;
}

 

posted @ 2023-08-04 11:33  忧愁的chafry  阅读(19)  评论(0编辑  收藏  举报