每日一題,防止癡呆 = =
一、題目大意
給定一個未排序的整數數組,找出最長連續序列的長度。
要求算法的時間複雜度爲 O(n)。
來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/longest-consecutive-sequence
二、題目思路以及AC代碼
最開始看到這道題還以爲是最長上升子序列呢 = =,仔細一看,原來不是。
思路一
先說一下我自己想到的思路,最後發現還是比官解複雜一點,但感覺出發點是一樣的。題目要求求數組中連續的序列,那麼我們就可以在遍歷到一個數x的時候,查看x向右可以最遠到哪個數,x向左最遠可以到哪個數,這樣的話,我們只要枚舉這些數,然後找到最長的序列即可,其中我們在查看某個數是否在數組中,可以提前用unorder_map去保存。
當我們在枚舉這些數列的時候,其實有點並查集的意思,如果我遍歷x的時候,發現y在x的連續數列中,那麼x肯定也在y的連續數列中,那麼這兩個連續數列就沒必要遍歷兩次了,所以我又採用了一個unordered_map來記錄該數是否已經遍歷過了,這樣整體每個數只會被遍歷一次,則複雜度爲O(n)。
思路二
做完之後,我去看了看題解的思路,和我的思路類似,感覺是又優化了一次。我的思路中,每次需要找一個數左右兩邊的邊界,而題解中將該數自身作爲左邊界,只去找右邊界,而這樣也不需要另外一個unordered_map來記錄是否遍歷過了,因爲如果當前數x在數組中存在x-1,則它就沒必要遍歷,因爲遍歷到x-1的時候,肯定會遍歷它,所以在空間上減少了一個unordered_map的空間,在時間上感覺兩種方法是差不多的。
AC代碼
思路一:
class Solution {
public:
int longestConsecutive(vector<int>& nums) {
unordered_map<int, bool> contains;
unordered_map<int, bool> vis;
int n_size = nums.size();
if (!n_size) return 0;
for (int i=0;i<n_size;i++) {
contains[nums[i]] = true;
}
int res = -1;
for (int i=0;i<n_size;i++) {
if (vis[nums[i]]) continue;
int cnt = 1;
int num = nums[i] - 1;
// 向左找
while (contains[num]) {
vis[num] = true;
cnt++;
num--;
}
// 向右找
num = nums[i] + 1;
while (contains[num]) {
vis[num] = true;
cnt++;
num++;
}
res = max(res, cnt);
}
return res;
}
};
思路二:
class Solution {
public:
int longestConsecutive(vector<int>& nums) {
unordered_map<int, bool> contains;
int n_size = nums.size();
if (!n_size) return 0;
for (int i=0;i<n_size;i++) {
contains[nums[i]] = true;
}
int res = -1;
for (int i=0;i<n_size;i++) {
if (contains[nums[i]-1]) continue;
int cnt = 1;
int num = nums[i] + 1;
while (contains[num]) {
cnt++;
num++;
}
res = max(res, cnt);
}
return res;
}
};
如果有問題,歡迎大家指正!!!