Friday, April 7, 2017

128. Longest Consecutive Sequence

三刷 06/2022
Version #1 HashSet
还是完全没有思路,看了答案才写出来
Time O(N)
Space O(N)
Runtime: 38 ms, faster than 78.17% of Java online submissions for Longest Consecutive Sequence.
Memory Usage: 74.5 MB, less than 58.96% of Java online submissions for Longest Consecutive Sequence.

class Solution {
    public int longestConsecutive(int[] nums) {
        Set<Integer> set = new HashSet<>();
        for (int num : nums) {
            set.add(num);
        }
        int max = 0;
        for (int num : nums) {
            if (!set.contains(num)) {
                continue;
            }
            // Thie is not the start number of a sequence
            int start = num, end = num;
            while (set.remove(start - 1)) {
                start--;
            }
            while (set.remove(end + 1)) {
                end++;
            }
            max = Math.max(max, end - start + 1);
        }
        return max;
    }
}

二刷
Version #4 Union Find Index
另外一个完全不同的思路是对index进行Union Find
感觉比我写的要好
Ref
https://leetcode.com/problems/longest-consecutive-sequence/discuss/41062/My-Java-Solution-using-UnionFound

Version #3 Union Find 2 HashMap
这道题的精华是说union find不一定用array表示
只有当key是 0 -> N - 1的时候 size[] id[]才适用
其他情况下可以用hashmap代替

13.12 %
class Solution {
    class UF {
        // key -> num, value -> size
        private Map<Integer, Integer> size;
        // key -> num, value -> parent
        public Map<Integer, Integer> id;
        public int maxSize;
        public UF(int[] nums) {
            size = new HashMap<>();
            id = new HashMap<>();
            for (int num : nums) {
                size.put(num, 1);
                id.put(num, num);
            }
            maxSize = 1;
        }
   
        private int root(int i) {
            while (id.get(i) != i) {
                int parent = id.get(i);
                id.put(i, id.get(parent));
                i = id.get(parent);
            }
            return i;
        }
   
        public void union(int p, int q) {
            int rootP = root(p);
            int rootQ = root(q);
            if (rootP == rootQ) {
                return;
            }
            if (size.get(rootP) < size.get(rootQ)) {
                id.put(rootP, rootQ);
                size.put(rootQ, size.get(rootP) + size.get(rootQ));
                maxSize = Math.max(maxSize, size.get(rootQ));
            } else {
                id.put(rootQ, rootP);
                size.put(rootP, size.get(rootP) + size.get(rootQ));
                maxSize = Math.max(maxSize, size.get(rootP));
            }
        }
    }

    public int longestConsecutive(int[] nums) {
        if (nums == null || nums.length == 0) {
            return 0;
        }
        UF uf = new UF(nums);
        for (int num : nums) {
            if (uf.id.keySet().contains(num + 1)) {
                uf.union(num, num + 1);
            }
            if (uf.id.keySet().contains(num - 1)) {
                uf.union(num, num - 1);
            }
        }
        return uf.maxSize;
    }
}



Version #2 HashSet
三刷
这个题的问题在于如果新来的num,它的num - 1,num + 1都有值的话
此时的num就不是一个边界
但是也要塞到hashmap里面因为如果6 来了 给你更新了5和7的长度为3
但是没有塞到hashmap里面
那么如果再来一个6,就会造成5和7的长度变成了7
所以这里把6塞进去相当于一个visited的作用,具体的value无所谓


16.88 %
class Solution {
    public int longestConsecutive(int[] nums) {
        // the length of sequence starts/ends with key
        Map<Integer, Integer> map = new HashMap<>();
        int max = 0;
        for (int num : nums) {
            if (map.containsKey(num)) {
                continue;
            }
            int left = map.getOrDefault(num - 1, 0);
            int right = map.getOrDefault(num + 1, 0);
            int sum = left + right + 1;
            max = Math.max(max, sum);
            // if (left == 0 || right == 0) {
            //     map.put(num, sum);
            // } else {
            //     map.put(num, 1);
            // }
            map.put(num, sum);
            map.put(num - left, sum);
            map.put(num + right, sum);
        }
        return max;
    }
}


一开始看了半天完全不会做
找了个hashset的答案,就是iterate整个array当确定当前值是某序列的第一个时,向后扫
然后扫到不能扫了,更新max
看了一刷的hashmap答案,感觉更好,就是给随便一个数就往前往后扫,扫到不能扫了 更新max right - left + 1
这两种方法都是一边检查一遍从set/map里面remove
74.81 %
class Solution {
    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 max = 0;
        for (int i = 0; i < nums.length; i++) {
            if (set.contains(nums[i]) && !set.contains(nums[i] - 1)) {
                int count = 0;
                int num = nums[i];
                while (set.contains(num)) {
                    set.remove(num);
                    num++;
                    count++;
                }
                max = Math.max(max, count);
            }
        }
        return max;
    }
}

一刷
Version #1 HashMap(Better than hashset)
Initialize a hashset and add every number into it.
Iterate through the number array.
For every current number, look for its 2 neighbors in the hashset.
Keep expanding the current consecutive sequence and remove every visited node.
Update the max length.
 71.13%

public class Solution {
    public int longestConsecutive(int[] nums) {
        if (nums == null || nums.length == 0) return 0;
        Set<Integer> set = new HashSet<>();
        int left = 0;
        int right = 0;
        for (int n : nums) set.add(n);
        int longest = 0;
        for (int n : nums) {
            if (set.contains(n)) {
                int down = n;
                while (set.contains(down - 1)) {
                    set.remove(down - 1);
                    down--;
                }
                int up = n;
                while (set.contains(up + 1)) {
                    set.remove(up + 1);
                    up++;
                }
                longest = Math.max(longest, up - down + 1);
            }
        }
        return longest;
    }
}

No comments:

Post a Comment