LeetCode 128 - Longest Consecutive Sequence


Jiaxin's LeetCode: Longest Consecutive Sequence @LeetCode
Given an unsorted array of integers, find the length of the longest consecutive elements sequence.
For example,
Given [100, 4, 200, 1, 3, 2],
The longest consecutive elements sequence is [1, 2, 3, 4]. Return its length: 4.
http://blog.csdn.net/itismelzp/article/details/51636555
使用一个Map保存连续序列两个边缘的值,这个值表示这个序列最大宽度。
如有nums = [1,2,3,4,5],则map.get(1) = map.get(5) = 5;
设有nums = [1,2,5,6,3,4].
    1 2 3 4 5 6
1: 1
2: 2 2
5: 2 2       1
6: 2 2       2 2
3: 3 2 3    2 2
4: 6 2 3 6 2 6
https://discuss.leetcode.com/topic/6148/my-really-simple-java-o-n-solution-accepted
We will use HashMap. The key thing is to keep track of the sequence length and store that in the boundary points of the sequence. For example, as a result, for sequence {1, 2, 3, 4, 5}, map.get(1) and map.get(5) should both return 5.
Whenever a new element n is inserted into the map, do two things:
  1. See if n - 1 and n + 1 exist in the map, and if so, it means there is an existing sequence next to n. Variables left and right will be the length of those two sequences, while 0 means there is no sequence and n will be the boundary point later. Store (left + right + 1) as the associated value to key n into the map.
  2. Use left and right to locate the other end of the sequences to the left and right of n respectively, and replace the value with the new length.
Everything inside the for loop is O(1) so the total time is O(n). 
public int longestConsecutive(int[] num) {
    int res = 0;
    HashMap<Integer, Integer> map = new HashMap<Integer, Integer>();
    for (int n : num) {
        if (!map.containsKey(n)) {
            int left = (map.containsKey(n - 1)) ? map.get(n - 1) : 0;
            int right = (map.containsKey(n + 1)) ? map.get(n + 1) : 0;
            // sum: length of the sequence n is in
            int sum = left + right + 1;
            map.put(n, sum);
            
            // keep track of the max length 
            res = Math.max(res, sum);
            
            // extend the length to the boundary(s)
            // of the sequence
            // will do nothing if n has no neighbors
            map.put(n - left, sum);
            map.put(n + right, sum);
        }
        else {
            // duplicates
            continue;
        }
    }
    return res;
}
Another ways is Sort and find longest increasing sequence. O(nlog(n)) Time. O(1) Space

* Solution: HashMap Space O(n) Time Complexity O(n) -- 限制O(n), 排序是O(nlog(n)) ---> 必定是空间换时间 * {100, 2, 3, 200, 1, 4}, For a give number 2
* first search increasing consecutive(right side), 3,4
* then search descending consecutive(left side), 1.
* Every node in the sequence has been visited, next time it will be skipped.
* At most, we will visit n node. --> O(n)
*
* Another ways is Sort and find longest increasing sequence. O(nlog(n)) Time. O(1) Space


http://rainykat.blogspot.com/2017/01/leetcodefg-128-longest-consecutive.html
Use HashMap to store val and its current length of consecutive elements(not necessarily final),
only updating and maintain max length on boundary points(n-left & n+right). 
Complexity: O(N)
    public int longestConsecutive(int[] num) {
        int len = 0;
        HashMap<Integer,Integer> map = new HashMap<Integer,Integer>();//<val,len>
        for(int n:num){
            if(!map.containsKey(n)){
                //1.check if n has conseq and update len
                int left = (map.containsKey(n-1))?map.get(n-1):0;
                int right = (map.containsKey(n+1))?map.get(n+1):0;
                int sum = left + right +1;
                map.put(n,sum);
                len = Math.max(sum,len);
                // 2.Union by only updating boundary(maintaining total len)
                // Leave middle k-v dirty to avoid cascading update
                map.put(n-left,sum);
                map.put(n+right,sum);
            }else{
                //duplicates
                continue;
            }
        }
        return len;
    }
https://discuss.leetcode.com/topic/9088/o-n-hashmap-java-solution
Use a hashmap to map a number to its longest consecutive sequence length, each time find a new consecutive sequence, only the begin number and end number need to be modified.
The code is right, but just difficult to explain and understand it's correctness. for example what Map<Integer, Integer> map stores, what's the key and value.
100, 5, 4, 200, 2, 3, 1
Map:
{100=1}
{100=1, 5=1}
{100=1, 4=2, 5=2}
{100=1, 4=2, 5=2, 200=1}
{2=1, 100=1, 4=2, 5=2, 200=1}
{2=4, 3=1, 100=1, 4=2, 5=4, 200=1}
{1=5, 2=4, 3=1, 100=1, 4=2, 5=5, 200=1}
    public int longestConsecutive(int[] num) {
        int longest = 0;
        Map<Integer, Integer> map = new HashMap<Integer, Integer>();
        for(int i = 0;i < num.length;i++){
            // if there is no duplicates, these two lines can be commented
            if(map.containsKey(num[i])) continue;
            map.put(num[i],1);
            
            int end = num[i];
            int begin = num[i];
            if(map.containsKey(num[i]+1))
                end = num[i] + map.get(num[i]+1);
            if(map.containsKey(num[i]-1))
                begin = num[i] - map.get(num[i]-1);
            longest = Math.max(longest, end-begin+1);
            map.put(end, end-begin+1);
            map.put(begin, end-begin+1);
        }
        return longest;
    }
X.
http://www.cnblogs.com/grandyang/p/4276225.html
    public int longestConsecutive(int[] nums) {
        int res = 0;
        Set<Integer> s = new HashSet<Integer>();
        for (int num : nums) s.add(num);
        for (int num : nums) {
            if (s.remove(num)) {
                int pre = num - 1, next = num + 1;
                while (s.remove(pre)) --pre;
                while (s.remove(next)) ++next;
                res = Math.max(res, next - pre - 1);
            }
        }
        return res;
    }
https://discuss.leetcode.com/topic/25493/simple-fast-java-solution-using-set
https://discuss.leetcode.com/topic/17980/another-accepted-java-o-n-solution/2
public int longestConsecutive(int[] num) {
  int max = 0;
  
  Set<Integer> set = new HashSet<Integer>();
  for (int i = 0; i < nums.length; i++) {
    set.add(nums[i]);
  }
  
  for (int i = 0; i < nums.length; i++) {
    int count = 1;
    
    // look left
    int num = nums[i];
    while (set.contains(--num)) {
      count++;
      set.remove(num);
    }
    
    // look right
    num = nums[i];
    while (set.contains(++num)) {
      count++;
      set.remove(num);
    }
    
    max = Math.max(max, count);
  }
  
  return max;
}
- This doesn't work for stream, as it first read all data
Using a set to collect all elements that hasn't been visited. search element will be O(1) and eliminates visiting element again.
public int longestConsecutive(int[] nums) {
    if(nums == null || nums.length == 0) return 0;
    
    Set<Integer> set = new HashSet<Integer>();
    
    for(int num: nums) set.add(num);//\\
    int max = 1;
    for(int num: nums) {
        if(set.remove(num)) {//num hasn't been visited
            int val = num;
            int sum = 1;
            while(set.remove(val-1)) val--;
            sum += num - val;
            
            val = num;
            while(set.remove(val+1)) val++;
            sum += val - num;
            
            max = Math.max(max, sum);
        }
    }
    return max;
}

https://discuss.leetcode.com/topic/6148/my-really-simple-java-o-n-solution-accepted
We will use HashMap. The key thing is to keep track of the sequence length and store that in the boundary points of the sequence. For example, as a result, for sequence {1, 2, 3, 4, 5}, map.get(1) and map.get(5) should both return 5.
Whenever a new element n is inserted into the map, do two things:
  1. See if n - 1 and n + 1 exist in the map, and if so, it means there is an existing sequence next to n. Variables left and right will be the length of those two sequences, while 0 means there is no sequence and n will be the boundary point later. Store (left + right + 1) as the associated value to key n into the map.
  2. Use left and right to locate the other end of the sequences to the left and right of n respectively, and replace the value with the new length.
Everything inside the for loop is O(1) so the total time is O(n). Please comment if you see something wrong. Thanks.
public int longestConsecutive(int[] num) {
    int res = 0;
    HashMap<Integer, Integer> map = new HashMap<Integer, Integer>();
    for (int n : num) {
        if (!map.containsKey(n)) {
            int left = (map.containsKey(n - 1)) ? map.get(n - 1) : 0;
            int right = (map.containsKey(n + 1)) ? map.get(n + 1) : 0;
            // sum: length of the sequence n is in
            int sum = left + right + 1;
            map.put(n, sum);
            
            // keep track of the max length 
            res = Math.max(res, sum);
            
            // extend the length to the boundary(s)
            // of the sequence
            // will do nothing if n has no neighbors
            map.put(n - left, sum);
            map.put(n + right, sum);
        }
        else {
            // duplicates
            continue;
        }
    }
    return res;
}
X. Use Hashset
https://leetcode.com/articles/longest-consecutive-sequence/
  • Time complexity : O(n).
    Although the time complexity appears to be quadratic due to the while loop nested within the forloop, closer inspection reveals it to be linear. Because the while loop is reached only when currentNum marks the beginning of a sequence (i.e. currentNum-1 is not present in nums), the while loop can only run for n iterations throughout the entire runtime of the algorithm. This means that despite looking like O(n \cdot n) complexity, the nested loops actually run in O(n + n) = O(n)time. All other computations occur in constant time, so the overall runtime is linear.
  public int longestConsecutive(int[] nums) {
    Set<Integer> num_set = new HashSet<Integer>();
    for (int num : nums) {
      num_set.add(num);
    }

    int longestStreak = 0;

    for (int num : num_set) {
      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;

  }
https://discuss.leetcode.com/topic/15383/simple-o-n-with-explanation-just-walk-each-streak
First turn the input into a set of numbers. That takes O(n) and then we can ask in O(1) whether we have a certain number.
Then go through the numbers. If the number n is the start of a streak (i.e., n-1 is not in the set), then test m = n+1, n+2, n+3, ... and stop at the first number m not in the set. The length of the streak is then simply m-n and we update our global best with that. Since we check each streak only once, this is overall O(n). This ran in 44 ms on the OJ, one of the fastest Python submissions.
   public int longestConsecutive(int[] nums) {
            Set<Integer> set = new HashSet<>();
            for(int n : nums) {
                set.add(n);
            }
            int best = 0;
            for(int n : set) {
                if(!set.contains(n - 1)) {  // only check for one direction
                    int m = n + 1;
                    while(set.contains(m)) {
                        m++;
                    }
                    best = Math.max(best, m - n);
                }
            }
            return best;
        }
http://www.programcreek.com/2013/01/leetcode-longest-consecutive-sequence-java/
public static int longestConsecutive(int[] num) {
 // if array is empty, return 0
 if (num.length == 0) {
  return 0;
 }
 
 Set<Integer> set = new HashSet<Integer>();
 int max = 1;
 
 for (int e : num)
  set.add(e);
 
 for (int e : num) {
  int left = e - 1;
  int right = e + 1;
  int count = 1;
 
  while (set.contains(left)) {
   count++;
   set.remove(left);
   left--;
  }
 
  while (set.contains(right)) {
   count++;
   set.remove(right);
   right++;
  }
 
  max = Math.max(count, max);
 }
 
 return max;
}
X. Best http://www.keithschwarz.com/interesting/code/?dir=longest-range
    public static int longestRange(int[] arr) {
        /* Begin by creating a hash table that holds all of the array
         * elements.
         */

        Set<Integer> values = new HashSet<Integer>();
        for (int value: arr)
            values.add(value);
        
        /* Keep track of the longest range we've seen so far.  Initially,
         * this is the empty range.
         */

        int longest = 0;
        
        /* Scan across the array, searching for the longest range of values
         * contained in that array.
         */

        for (int value: arr) {
            /* To avoid unnecessary work, don't process this element if
             * we already did.  To mark that it has been processed, we
             * remove the element.  Since Java's Set#remove function
             * returns whether the element was removed successfully, we
             * can combine the test/remove operation into one.
             */

            if (!values.remove(value)) continue;
            
            /* Track how many total elements are in the range containing
             * the current element.  Initially this is one, because the
             * range contains this element.
             */

            int rangeLength = 1;
            
            /* See how many elements are greater than the current value
             * and contained in the range.  To avoid integer overflow,
             * at each step we track whether the element we're about to
             * probe is greater than the current element; on an overflow,
             * this will be false.
             */

            for (int i = 1; value + i > value; ++i) {
                /* Again, combine the test/remove operation into
                 * one.
                 */

                if (!values.remove(value + i)) break;
                
                ++rangeLength;
            }
            
            /* Using similar logic, see how many elements in the range
             * are smaller than the current value.
             */

            for (int i = 1; value - i < value; ++i) {
                if (!values.remove(value - i)) break;
                ++rangeLength;
            }
            
            /* Update the length of the longest range we've seen so far. */
            if (longest < rangeLength) longest = rangeLength;
        }
        
        /* Hand back the length of the longest range we encountered. */
        return longest;
    }

 private int findConsecutive(HashSet<Integer> set, int num, int step) {  
   int len = 0;  
   while (set.contains(num)) {  
     ++len;  
     set.remove(num);  
     num += step;  
   }  
   return len;  
 }  
   
 public int longestConsecutive(int[] nums) {  
   HashSet<Integer> set = new HashSet<Integer>();  
   // find all   
   for (int num : nums) {  
     set.add(num);  
   }  
   // find longest seq  
   int maxLen = 0;  
   for (int num : nums) {  
     if (set.contains(num)) {  
       set.remove(num); 
       int len = 1 + findConsecutive(set, num-1, -1);  
       len += findConsecutive(set, num+1, 1);  
       maxLen = Math.max(maxLen, len);  
     }  
   }  
   return maxLen;  
 }  

 private int findConsecutive(HashMap<Integer, Boolean> map, int num, int step) {  
   int len = 0;  
   while (map.containsKey(num)) {  
     ++len;  
     map.put(num, true);  
     num += step;  
   }  
   return len;  
 }  
   
 public int longestConsecutive(int[] nums) {  
   HashMap<Integer, Boolean> map = new HashMap<Integer, Boolean>();  
   // find all   
   for (int num : nums) {  
     map.put(num, false);  
   }  
   // find longest seq  
   int maxLen = 0;  
   for (int num : nums) {  
     if (!map.get(num)) {  
       map.put(num, true);  
       int len = 1 + findConsecutive(map, num-1, -1);  
       len += findConsecutive(map, num+1, 1);  
       maxLen = Math.max(maxLen, len);  
     }  
   }  
   return maxLen;  
 }  


/* Per definition of the map,  
  * - l maps to the len of a left range where l itself is the rightmost element;  
  * - r maps to the len of a right range where r is the leftmost element.  
  * After merging left and right ranges into one,  
  * - the original leftmost of left range becomes the new leftmost;  
  * - the original rightmost of right range becomes the new rightmost.  
  */  
 public int merge(HashMap<Integer, Integer> map, int l, int r) {  
   int left = l - map.get(l) + 1;  
   int right = r + map.get(r) - 1;  
   int range = right - left + 1;  
   map.put(left, range);  
   map.put(right, range);  
   return range;  
 }  
   
 public int longestConsecutive(int[] nums) {  
   // Map each number to the maxLen of the range that contains the number.  
   // Only need to maintain length of range boundaries  
   // since each time we either merge from left or merge from right.  
   HashMap<Integer, Integer> map = new HashMap<Integer, Integer>();  
   int maxLen = (nums.length==0) ? 0 : 1;  
   for (int num : nums) {  
     if (!map.containsKey(num)) {  
       map.put(num, 1);  
       if (map.containsKey(num-1)) {  
         maxLen = Math.max(maxLen, merge(map, num-1, num));  
       }  
       if (map.containsKey(num+1)) {  
         maxLen = Math.max(maxLen, merge(map, num, num+1));  
       }  
     }  
   }  
   return maxLen;  
 }  
https://reeestart.wordpress.com/2016/06/14/google-longest-consecutive-sequencesubstring/
leetcode原题就不多说了。HashSet with remove, 虽然有两层loop,但是time complexity还是O(n).

Code for Sequence
  public int longestConsecutive(int[] nums) {
    if (nums == null || nums.length == 0) {
      return 0;
    }
     
    Set<Integer> set = new HashSet<>();
    for (int num : nums) {
      set.add(num);
    }
     
    int result = 0;
    for (int num : nums) {
      set.remove(num);
      int l = num - 1;
      int r = num + 1;
      int len = 1;
      while (set.contains(l)) {
        set.remove(l);
        l--;
        len++;
      }
      while (set.contains(r)) {
        set.remove(r);
        r++;
        len++;
      }
       
      result = Math.max(result, len);
    }
    return result;
  }
Code for Substring

  public int longestConsecutive(int[] nums) {
    if (nums == null || nums.length == 0) {
      return 0;
    }
    int result = 0;
    int len = 1;
    for (int i = 1; i < nums.length; i++) {
      if (nums[i] == nums[i - 1] + 1) {
        len++;
      }
      else {
        result = Math.max(result, len);
        len = 1;
      }
    }
    result = Math.max(result, len);
    return result;
  }
http://www.geeksforgeeks.org/longest-consecutive-subsequence/

X. Union-find
https://xiangliangyang.gitbooks.io/leetcode/content/411-union-find/55-longest-consecutive-sequence.html

https://leetcode.com/problems/longest-consecutive-sequence/discuss/41062/My-Java-Solution-using-UnionFound
    Map<Integer, Integer> map = new HashMap<>(); // parent
    Map<Integer, Integer> c = new HashMap<>(); // count
    int res=1;
    
    public int longestConsecutive(int[] a) {
        if(a.length==0) return 0;
        for(int i=0;i<a.length;i++){ 
            int cur = a[i];
            if(map.containsKey(cur)) continue;

            map.put(cur,cur);
            c.put(cur, 1);
            
            if(map.containsKey(cur-1)) union(cur-1, cur);
            if(map.containsKey(cur+1)) union(cur+1, cur);
        }

        return res;
    }
    
    int find(int x){
        if(map.get(x)==x) return x;
        int par = find(map.get(x));
        map.put(x, par); // path compression
        return par;
    }
    
    void union(int x, int y){
        int px = find(x);
        int py = find(y);
        
        // union by size
        int newCount = c.get(py)+c.get(px);
        if(c.get(px)<c.get(py)){
            map.put(px, py);    
            c.put(py, newCount); 
        }else{
            map.put(py, px);    
            c.put(px, newCount); 
        }
        
        res=Math.max(res, newCount);
    }
http://www.jianshu.com/p/e6b955ca208f
我提前做了一个size数组专门用来记录大小,并且当合并树的时候可以使该算法更快。
当我们需要根据value将index连接起来,而index又相邻时,
Union Find 用代码解决了这个 连接结点 的问题。
参考网址:
http://www.programcreek.com/2013/01/leetcode-longest-consecutive-sequence-java/
  public int longestConsecutive(int[] nums) {
    if (nums == null || nums.length == 0)
      return 0;
    Union union = new Union(nums.length);
    HashMap<Integer, Integer> helper = new HashMap<Integer, Integer>();
    for (int i = 0; i < nums.length; i++) {
      if (helper.containsKey(nums[i])) {
        continue;
      }
      helper.put(nums[i], i);
      if (helper.containsKey(nums[i] - 1))
        union.union(i, helper.get(nums[i] - 1));
      if (helper.containsKey(nums[i] + 1))
        union.union(i, helper.get(nums[i] + 1));
    }
    return union.maxUnion();
  }

  private class Union {
    int[] unions;
    int[] size;
    int count;

    Union(int n) {
      unions = new int[n];
      size = new int[n];
      count = n;
      for (int i = 0; i < n; i++) {
        unions[i] = i;
        size[i] = 1;
      }
    }

    /** return the group id of this index */
    int find(int p) {
      if (p >= unions.length)
        return -1;
      while (p != unions[p])
        p = unions[p];
      return p;
    }

    /** test whether two indexs are connectted */
    boolean connected(int p, int q) {
      p = find(p);
      q = find(q);
      return p == q;
    }

    /** connect two components by making their group id equal */
    void union(int p, int q) {
      p = find(p);
      q = find(q);
      if (size[p] > size[q]) {
        size[p] += size[q];
        unions[q] = p;
      } else {
        size[q] += size[p];
        unions[p] = q;
      }
      count--;
    }

    /** return the maximum size of components */
    int maxUnion() {
      int max = 1;
      for (int i = 0; i < unions.length; i++) {
        max = Math.max(max, size[i]);
      }
      return max;
    }

  }
http://blog.csdn.net/dm_vincent/article/details/7655764
https://discuss.leetcode.com/topic/29286/my-java-solution-using-unionfound/3
http://algs4.cs.princeton.edu/15uf/


performance of union-find algorithms
I implemented the following code which is a slight improvement over the one suggested in the original post. I have optimized the retrieval of the maxUnion (getHighestRank in my case) to O(1).
Also, @liangyue268 Weighted Union Find with Path Compression isn't exactly O(nlogn) but more close to O(n). This is because the path compression function (see find operation) exhibits growth which follows the Inverse Ackermann Function. Both union and find are not exactly 1 but are very very very close to 1, visit here for more details.
    public int longestConsecutive(int[] nums) {
        final int length = nums.length;
        if (length <= 1) return length;
        
        final Map<Integer, Integer> elementIndexMap = new HashMap();
        final UnionFind uf = new UnionFind(length);
        for (int p = 0; p < length; p++) {
            final int i = nums[p];
            if (elementIndexMap.containsKey(i)) continue;
            if (elementIndexMap.containsKey(i+1)) uf.union(p, elementIndexMap.get(i+1));
            if (elementIndexMap.containsKey(i-1)) uf.union(p, elementIndexMap.get(i-1));
            elementIndexMap.put(i, p);
        }
        return uf.getHighestRank();
    }
    
    private final class UnionFind {
        final private int[] sequenceTree;
        final private int[] rank;
        private int highestRank;
        
        UnionFind(int length) {
            sequenceTree = new int[length];
            rank = new int[length];
            highestRank = 1;
            for (int i = 0; i < length; i++) {
                sequenceTree[i] = i;
                rank[i] = 1;
            }
        }
        
        void union(int p, int q) {
            final int pId = find(p); final int qId = find(q);
            
            if (pId == qId) return;
            
            int localHighestRank = 1;
            if (rank[pId] < rank[qId]) {
                sequenceTree[pId] = qId;
                rank[qId] += rank[pId];
                localHighestRank = rank[qId];
            } else {
                sequenceTree[qId] = pId;
                rank[pId] += rank[qId];
                localHighestRank = rank[pId];
            }
            highestRank = Math.max(highestRank, localHighestRank);
        }
        
        int find(int p) {
            while (p != sequenceTree[p]) {
                sequenceTree[p] = sequenceTree[sequenceTree[p]];
                p = sequenceTree[p];
            }
            return p;
        }
        
        int getHighestRank() { return highestRank; }
    }
        public int longestConsecutive(int[] nums) {
            UF uf = new UF(nums.length);
            Map<Integer,Integer> map = new HashMap<Integer,Integer>(); // <value,index>
            for(int i=0; i<nums.length; i++){
                if(map.containsKey(nums[i])){
                    continue;
                }
                map.put(nums[i],i);
                if(map.containsKey(nums[i]+1)){
                    uf.union(i,map.get(nums[i]+1));
                }
                if(map.containsKey(nums[i]-1)){
                    uf.union(i,map.get(nums[i]-1));
                }
            }
            return uf.maxUnion();
        }
    }
    
    class UF{
        private int[] list;
        public UF(int n){
            list = new int[n];
            for(int i=0; i<n; i++){
                list[i] = i;
            }
        }
        
        private int root(int i){
            while(i!=list[i]){
                list[i] = list[list[i]];
                i = list[i];
            }
            return i;
        }
        
        public boolean connected(int i, int j){
            return root(i) == root(j);
        }
        
        public void union(int p, int q){
          int i = root(p);
          int j = root(q);
          list[i] = j;
        }
        
        // returns the maxium size of union
        public int maxUnion(){ // O(n)
            int[] count = new int[list.length];
            int max = 0;
            for(int i=0; i<list.length; i++){
                count[root(i)] ++;
                max = Math.max(max, count[root(i)]);
            }
            return max;
        }

X.
  public int longestConsecutive(int[] nums) {
    if (nums.length == 0) {
      return 0;
    }

    Arrays.sort(nums);

    int longestStreak = 1;
    int currentStreak = 1;

    for (int i = 1; i < nums.length; i++) {
      if (nums[i] != nums[i - 1]) {
        if (nums[i] == nums[i - 1] + 1) {
          currentStreak += 1;
        } else {
          longestStreak = Math.max(longestStreak, currentStreak);
          currentStreak = 1;
        }
      }
    }

    return Math.max(longestStreak, currentStreak);

  }
X. DP
http://fisherlei.blogspot.com/2013/02/leetcode-longest-consecutive-sequence.html
For each num, define D[num] as the longest consecutive sequence from k to num,  0<k<num

So D[num] = D[num-1] +1   if num-1 in the map
                  =0                      if num-1  not in the map

But unfortunately, the unordered_map doesn't keep any order of sequence. It's hard to do the DP via a loop.

Here can use Memorization to optimize the code. Since for each fresh node, it only visits once. It is O(n) code.

And in the code , the second 'for' loop and the third 'for' loop could be merged together, but here keep them separated for readability.

1:       int longestConsecutive(vector<int> &num) {  
2:            unordered_map<int, int> hashmap;  
3:            vector<int> length(num.size(),0);  
4:            for(int i =0; i< num.size(); i++)  
5:            {  
6:                 hashmap[num[i]]=i;  
7:            }  
8:            for(int i =0; i< num.size(); i++)  
9:            {  
10:                 // skip the node, which already calculate the length  
11:                 if(length[i] > 0) continue;                 
12:                 length[i] = consecutiveLength(num[i], hashmap, length);  
13:            }  
14:            int maxV = INT_MIN;  
15:            for(int i =0; i< num.size(); i++)  
16:            {  
17:                 maxV = length[i]>maxV?length[i]:maxV;  
18:            }  
19:            return maxV;  
20:       }  
21:       int consecutiveLength(int num, unordered_map<int, int>& hashmap, vector<int>& length)  
22:       {  
23:            if(hashmap.find(num) == hashmap.end()) return 0;  
24:            int index = hashmap[num];  
25:            // skip the node, which already calculate the length  
26:            if(length[index] > 0) return length[index];  
27:            else  
28:            {  
29:                 // hit each fresh node only once  
30:                 length[index] = consecutiveLength(num - 1, hashmap, length) + 1;  
31:                 return length[index];  
32:            }  
33:       } 

X. https://leetcode.com/articles/longest-consecutive-sequence/
Time complexity : O(n^3).
The outer loop runs exactly n times, and because currentNum increments by 1 during each iteration of the while loop, it runs in O(n) time. Then, on each iteration of the while loop, an O(n) lookup in the array is performed. Therefore, this brute force algorithm is really three nested O(n) loops, which compound multiplicatively to a cubic runtime.
  private boolean arrayContains(int[] arr, int num) {
    for (int i = 0; i < arr.length; i++) {
      if (arr[i] == num) {
        return true;
      }
    }

    return false;
  }

  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;

  }
Read full article from Jiaxin's LeetCode: Longest Consecutive Sequence @LeetCode

Labels

LeetCode (1432) GeeksforGeeks (1122) LeetCode - Review (1067) Review (882) Algorithm (668) to-do (609) Classic Algorithm (270) Google Interview (237) Classic Interview (222) Dynamic Programming (220) DP (186) Bit Algorithms (145) POJ (141) Math (137) Tree (132) LeetCode - Phone (129) EPI (122) Cracking Coding Interview (119) DFS (115) Difficult Algorithm (115) Lintcode (115) Different Solutions (110) Smart Algorithm (104) Binary Search (96) BFS (91) HackerRank (90) Binary Tree (86) Hard (79) Two Pointers (78) Stack (76) Company-Facebook (75) BST (72) Graph Algorithm (72) Time Complexity (69) Greedy Algorithm (68) Interval (63) Company - Google (62) Geometry Algorithm (61) Interview Corner (61) LeetCode - Extended (61) Union-Find (60) Trie (58) Advanced Data Structure (56) List (56) Priority Queue (53) Codility (52) ComProGuide (50) LeetCode Hard (50) Matrix (50) Bisection (48) Segment Tree (48) Sliding Window (48) USACO (46) Space Optimization (45) Company-Airbnb (41) Greedy (41) Mathematical Algorithm (41) Tree - Post-Order (41) ACM-ICPC (40) Algorithm Interview (40) Data Structure Design (40) Graph (40) Backtracking (39) Data Structure (39) Jobdu (39) Random (39) Codeforces (38) Knapsack (38) LeetCode - DP (38) Recursive Algorithm (38) String Algorithm (38) TopCoder (38) Sort (37) Introduction to Algorithms (36) Pre-Sort (36) Beauty of Programming (35) Must Known (34) Binary Search Tree (33) Follow Up (33) prismoskills (33) Palindrome (32) Permutation (31) Array (30) Google Code Jam (30) HDU (30) Array O(N) (29) Logic Thinking (29) Monotonic Stack (29) Puzzles (29) Code - Detail (27) Company-Zenefits (27) Microsoft 100 - July (27) Queue (27) Binary Indexed Trees (26) TreeMap (26) to-do-must (26) 1point3acres (25) GeeksQuiz (25) Merge Sort (25) Reverse Thinking (25) hihocoder (25) Company - LinkedIn (24) Hash (24) High Frequency (24) Summary (24) Divide and Conquer (23) Proof (23) Game Theory (22) Topological Sort (22) Lintcode - Review (21) Tree - Modification (21) Algorithm Game (20) CareerCup (20) Company - Twitter (20) DFS + Review (20) DP - Relation (20) Brain Teaser (19) DP - Tree (19) Left and Right Array (19) O(N) (19) Sweep Line (19) UVA (19) DP - Bit Masking (18) LeetCode - Thinking (18) KMP (17) LeetCode - TODO (17) Probabilities (17) Simulation (17) String Search (17) Codercareer (16) Company-Uber (16) Iterator (16) Number (16) O(1) Space (16) Shortest Path (16) itint5 (16) DFS+Cache (15) Dijkstra (15) Euclidean GCD (15) Heap (15) LeetCode - Hard (15) Majority (15) Number Theory (15) Rolling Hash (15) Tree Traversal (15) Brute Force (14) Bucket Sort (14) DP - Knapsack (14) DP - Probability (14) Difficult (14) Fast Power Algorithm (14) Pattern (14) Prefix Sum (14) TreeSet (14) Algorithm Videos (13) Amazon Interview (13) Basic Algorithm (13) Codechef (13) Combination (13) Computational Geometry (13) DP - Digit (13) LCA (13) LeetCode - DFS (13) Linked List (13) Long Increasing Sequence(LIS) (13) Math-Divisible (13) Reservoir Sampling (13) mitbbs (13) Algorithm - How To (12) Company - Microsoft (12) DP - Interval (12) DP - Multiple Relation (12) DP - Relation Optimization (12) LeetCode - Classic (12) Level Order Traversal (12) Prime (12) Pruning (12) Reconstruct Tree (12) Thinking (12) X Sum (12) AOJ (11) Bit Mask (11) Company-Snapchat (11) DP - Space Optimization (11) Dequeue (11) Graph DFS (11) MinMax (11) Miscs (11) Princeton (11) Quick Sort (11) Stack - Tree (11) 尺取法 (11) 挑战程序设计竞赛 (11) Coin Change (10) DFS+Backtracking (10) Facebook Hacker Cup (10) Fast Slow Pointers (10) HackerRank Easy (10) Interval Tree (10) Limited Range (10) Matrix - Traverse (10) Monotone Queue (10) SPOJ (10) Starting Point (10) States (10) Stock (10) Theory (10) Tutorialhorizon (10) Kadane - Extended (9) Mathblog (9) Max-Min Flow (9) Maze (9) Median (9) O(32N) (9) Quick Select (9) Stack Overflow (9) System Design (9) Tree - Conversion (9) Use XOR (9) Book Notes (8) Company-Amazon (8) DFS+BFS (8) DP - States (8) Expression (8) Longest Common Subsequence(LCS) (8) One Pass (8) Quadtrees (8) Traversal Once (8) Trie - Suffix (8) 穷竭搜索 (8) Algorithm Problem List (7) All Sub (7) Catalan Number (7) Cycle (7) DP - Cases (7) Facebook Interview (7) Fibonacci Numbers (7) Flood fill (7) Game Nim (7) Graph BFS (7) HackerRank Difficult (7) Hackerearth (7) Inversion (7) Kadane’s Algorithm (7) Manacher (7) Morris Traversal (7) Multiple Data Structures (7) Normalized Key (7) O(XN) (7) Radix Sort (7) Recursion (7) Sampling (7) Suffix Array (7) Tech-Queries (7) Tree - Serialization (7) Tree DP (7) Trie - Bit (7) 蓝桥杯 (7) Algorithm - Brain Teaser (6) BFS - Priority Queue (6) BFS - Unusual (6) Classic Data Structure Impl (6) DP - 2D (6) DP - Monotone Queue (6) DP - Unusual (6) DP-Space Optimization (6) Dutch Flag (6) How To (6) Interviewstreet (6) Knapsack - MultiplePack (6) Local MinMax (6) MST (6) Minimum Spanning Tree (6) Number - Reach (6) Parentheses (6) Pre-Sum (6) Probability (6) Programming Pearls (6) Rabin-Karp (6) Reverse (6) Scan from right (6) Schedule (6) Stream (6) Subset Sum (6) TSP (6) Xpost (6) n00tc0d3r (6) reddit (6) AI (5) Abbreviation (5) Anagram (5) Art Of Programming-July (5) Assumption (5) Bellman Ford (5) Big Data (5) Code - Solid (5) Code Kata (5) Codility-lessons (5) Coding (5) Company - WMware (5) Convex Hull (5) Crazyforcode (5) DFS - Multiple (5) DFS+DP (5) DP - Multi-Dimension (5) DP-Multiple Relation (5) Eulerian Cycle (5) Graph - Unusual (5) Graph Cycle (5) Hash Strategy (5) Immutability (5) Java (5) LogN (5) Manhattan Distance (5) Matrix Chain Multiplication (5) N Queens (5) Pre-Sort: Index (5) Quick Partition (5) Quora (5) Randomized Algorithms (5) Resources (5) Robot (5) SPFA(Shortest Path Faster Algorithm) (5) Shuffle (5) Sieve of Eratosthenes (5) Strongly Connected Components (5) Subarray Sum (5) Sudoku (5) Suffix Tree (5) Swap (5) Threaded (5) Tree - Creation (5) Warshall Floyd (5) Word Search (5) jiuzhang (5)

Popular Posts