0
点赞
收藏
分享

微信扫一扫

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


​​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.

class Solution {
public int longestConsecutive(int[] nums) {
int n = nums.length;
if(n<=1){
return n;
}
HashSet<Integer> set = new HashSet<>();
for(int a : nums){
set.add(a);
}
int max = 1;
//虽然是两层循环, 但是每个元素最多访问两次, 所以时间复杂度是O(N)
for(int i=0; i<n; i++){
int cur = nums[i];
//如果不存在nums[i]-1, 说明nums[i]是一个序列的最小值, 接下来看看这个序列的长度
if(!set.contains(cur-1)){
int len = 1;
while(set.contains(cur+1)){
len++;
cur++;
}
max = Math.max(max, len);
}
}
return max;
}
}

第一次做; 使用哈希表, 将暴力解法变成了时间复杂度为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;
}
}


举报

相关推荐

0 条评论