题目:
给定一个未排序的整数数组 nums ,找出数字连续的最长序列(不要求序列元素在原数组中连续)的长度。
请你设计并实现时间复杂度为 O(n) 的算法解决此问题。
示例 1:
输入: nums = [100,4,200,1,3,2]
输出: 4
解释: 最长数字连续序列是 [1, 2, 3, 4]。它的长度为 4。
示例 2:
输入: nums = [0,3,7,2,5,8,4,6,0,1]
输出: 9
示例 3:
输入: nums = [1,0,1,2]
输出: 3
动态规划做法:
阅读这道题的时候,看到连续,最长,马上就想到了动态规划来做,感觉比较像最长递增子序列这道题。 代码如下:
class Solution {
public int longestConsecutive(int[] nums) {
int n = nums.length;
int[] dp = new int[n];
Arrays.sort(nums);
Arrays.fill(dp, 1);
int ans = 0;
for (int i = 0; i < n; i++) {
for (int j = 0; j < i; j++) {
if (nums[i] == nums[j] + 1) {
dp[i] = Math.max(dp[i], dp[j] + 1);
}
}
ans = Math.max(ans, dp[i]);
}
return ans;
}
}
虽然个人感觉这种做法比较好理解,但是也超时了,力扣上时间复杂度要求为O(n)。。。。。 所以要找到别的方法,但是感觉动态规划应该是可以优化的?这一块没有去细想
哈希解法
这道题的本质上是在O(1)时间内找到某一个整数是否存在,我们可以考虑使用哈希表数据结构去存储每一个数是否出现过,再去遍历原数组,但是还有一个问题,在循环的时候肯定还有一层while操作去判断连续的序列,就不是O(n)了,所以就涉及到一个关键优化,每一次循环的时候去判断当前这个数的前一个数是否出现过,如果出现过,我们必定有一次已经循环过当前这个数了,所以可以直接跳过,所以添加了这个优化之后,我们每一次循环实际上从每个连续序列的开头开始操作的,这么一想,好像时间复杂度就是O(n)了,上代码
class Solution {
public int longestConsecutive(int[] nums) {
Map<Integer,Integer> map = new HashMap();
int n = nums.length;
int ans = 0;
for(int i = 0; i < n; i++)
map.put(nums[i],1);
for(int i = 0;i < n; i++) {
if(map.containsKey(nums[i] - 1)) continue;
int next = nums[i] + 1;
int num = 1;
while(map.containsKey(next)){
num++;
next++;
}
if(num > n / 2) return num;
ans = Math.max(num,ans);
}
return ans;
}
}
实际上还有一个优化,没有这个优化力扣是过不了的
if(num > n / 2) return num;
当前的连续序列的长度最终计算大于总的序列长度的一半的时候,就肯定是最长的了,所以就可以结束循环了。 力扣上必须加这个优化才能过。。。
总的来说,这道题就是典型的利用哈希表进行空间换时间的操作,动态规划也可以做,但是需要优化,目前还没有去想,印象中和最长递增子序列的优化应该是有点像的。以后再来填坑吧