128. Longest Consecutive Sequence - cocoder39/coco39_LC GitHub Wiki

128. Longest Consecutive Sequence

  • (1) optimal: mp[i] = j where j is the length of the consecutive sequence that containing i. tip: mp[num] = len. (1) insert num into map (2) why not mp[num] = a random number since we would only check the length of boundary element. for elements within a consecutive sequence and are not boundaries, we only check if it appeared before? Answer: make mp[num] consistent with mp[num - len] or mp[num+len] when num is exactly the boundary. we can also switch the position.
mp[num] = 0; 
mp[num - left_len] = len;
mp[num + right_len] = len;
int longestConsecutive(vector<int>& nums) {
        int res = 0;
        unordered_map<int, int> mp; //seq[i] is length of a consecutive sequence containing i
        for (auto num : nums) {
            if (mp.find(num) == mp.end()) { //ignore repeat num
                int left_len = mp.find(num - 1) != mp.end() ? mp[num - 1] : 0;
                int right_len = mp.find(num + 1) != mp.end() ? mp[num + 1] : 0;
                int len = left_len + right_len + 1;
                mp[num - left_len] = len;
                mp[num + right_len] = len;
                mp[num] = len; 
                res = max(res, len);
            }
        }
        return res;
    }
  • (2) O(n * log n) sort
  • (3) bucket sort, O(n) time. But we need check the max_size() that a vector can handle. if the input includes INT_MIN and INT_MAX, then high - low + 1 = 2^31 - 1 - (-2^31) + 1 = 2^32 > 2^32 - 1 = max of unsigned int. (size_type is unsigned int). So ask if there is bound for input numbers
int longestConsecutive(vector<int>& nums) {
        int low = INT_MAX;
        int high = INT_MIN;
        for (auto num : nums) {
            low = min(low, num);
            high = max(high, num);
        }
        
        vector<bool> visited(high - low + 1);
        for (auto num : nums) {
            visited[num - low] = true;
        }
        
        int res = 0;
        int cur = 0;
        for (long long i = 0; i < visited.size(); i++) {
            if (! visited[i]) {
                cur = 0;
            } else {
                cur++;
                res = max(res, cur);
            }
        }
        return res;
    }
  • (4) union find. ametrized O(n)
class UnionFind {
public:
    UnionFind(int N) {
        for (int i = 0; i < N; i++) {
            parent.push_back(i);
        }
        sz = vector<int>(N, 1);
    }
    void unite(int i, int j) {
        int p = root(i);
        int q = root(j);
        if (p == q) return;
            
        if (sz[p] < sz[q]) {
            parent[p] = q;
            sz[q] += sz[p];
        } else {
            parent[q] = p;
            sz[p] += sz[q];
        }
    }
    bool isConnected(int i, int j) {
        return root(i) == root(j);
    }
    int getMaxSz() {
        int res = 0;
        for (auto i : sz) {
            res = max(res, i);
        }
        return res;
    }
private:
    vector<int> parent;
    vector<int> sz;
    int root(int i) {
        while (i != parent[i]) {
            parent[i] = parent[parent[i]];
            i = parent[i];
        }
        return i;
    }
};

class Solution {
public:
    int longestConsecutive(vector<int>& nums) {
        int sz = nums.size();
        UnionFind uf(sz);
        
        unordered_map<int, int> mp;
        for (int i = 0; i < sz; i++) {
            if (mp.find(nums[i]) != mp.end())   continue;
            mp[nums[i]] = i;
            if (mp.find(nums[i] - 1) != mp.end())   uf.unite(i, mp[nums[i] - 1]);
            if (mp.find(nums[i] + 1) != mp.end())   uf.unite(i, mp[nums[i] + 1]);
        }
        return uf.getMaxSz();
    }
};

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Aug. 17, 2020

Option 1: looks like O(N^2) time complexity but it is actually O(N). Executing while loop only for the left most item in a range if num - 1 not in st

def longestConsecutive(self, nums: List[int]) -> int:
        st = set(nums)
        max_len = 0
        for num in st:
            if num - 1 not in st:
                cur_len = 1
                while num + 1 in st:
                    cur_len += 1
                    num += 1
                max_len = max(max_len, cur_len)
        return max_len

Option 2: merge resulted range while introducing new num

def longestConsecutive(self, nums: List[int]) -> int:
        # mp[left] = right, mp[right] = left
        left = {}
        right = {}
        seen = set(nums)
        for num in seen:
            merged = False
            while num - 1 in left or num + 1 in right:
                merged = True
                if num - 1 in left: # num may contribute
                    l = left[num-1]
                    r = right[num] if num in right else num
                    del left[num-1]
                    if num in right:
                        del right[num]
                    left[r] = l
                    right[l] = r
                elif num + 1 in right:
                    r = right[num+1]
                    l = left[num] if num in left else num
                    del right[num+1]
                    if num in left:
                        del left[num]
                    left[r] = l
                    right[l] = r
            if not merged:
                left[num] = num
                right[num] = num
                
        length = 0
        for k, v in left.items():
            length = max(length, k-v+1)
        return length

Option 3: Union find

def longestConsecutive(self, nums: List[int]) -> int:
        if not nums:
            return 0
        st = set(nums)
        
        parent = {}
        size = {}
        for num in st:
            parent[num] = num
            size[num] = 1
        
        def root(i):
            while i != parent[i]:
                i = parent[parent[i]]
            return parent[i]
        
        def union(i, j):
            p, q = root(i), root(j)
            if p == q:
                return
            if size[p] < size[q]:
                parent[p] = q
                size[q] += size[p]
            else:
                parent[q] = p
                size[p] += size[q]
        
        for num in st:
            if num - 1 in st:
                union(num-1, num)
            if num + 1 in st:
                union(num, num+1)
        
        return max(size.values())
⚠️ **GitHub.com Fallback** ⚠️