剑指 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; }