Longest Consecutive Sequence

https://leetcode.com/problems/longest-consecutive-sequence/

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.

Your algorithm should run in O(n) complexity.

解题思路:

这道题的难度在于用O(n)的时间。原来的数组没有排序,如果先排序,必然要花费O(nlogn)的时间,不符合要求。根据经验和直觉,可能是用O(n)的时间去遍历数组,然后借助HashMap,花费O(1)的时间去找某些元素在不在数组中。

按照这样的思路往下想,对于num[i]去寻找它的左侧和右侧邻接的元素,直到在num中不存在,这时更新长度。因为每个数字只能存在于唯一的一个consecutive sequence里,否则这两个sequence就是相连的。

所以,这里拓展过的元素就完全可以从set中删掉了。后面再遍历到的num[j]就可以直接跳过,因为它属于的最长consecutive sequence前面已经找出了。

这样,整体的时间复杂度一定是O(n)。

下面的代码使用了HashMap,同时对num中出现的数字计数。

public class Solution {

    public int longestConsecutive(int[] num) {

        Map<Integer, Integer> numMap = new HashMap<Integer, Integer>();

        for(int i = 0; i < num.length; i++){

            if(numMap.containsKey(num[i])){

                numMap.put(num[i], numMap.get(num[i]) + 1);

            }else{

                numMap.put(num[i], 1);

            }

        }

        

        int longestLength = 0;

        

        for(int i = 0; i < num.length; i++){

            int currentLength = 0;

            int next = num[i];

            while(numMap.containsKey(next) && numMap.get(next) > 0){

                numMap.put(next, numMap.get(next) - 1);

                currentLength++;

                next++;

            }

            

            int previous = num[i] - 1;

            while(numMap.containsKey(previous) && numMap.get(previous) > 0){

                numMap.put(previous, numMap.get(previous) - 1);

                currentLength++;

                previous--;

            }

            longestLength = Math.max(longestLength, currentLength);

        }

        

        return longestLength;

    }

}

后来发现根本没必要,因为一个数字即使出现多次,还是只能出现在一个consecutive sequence里,换成set。

public class Solution {

    public int longestConsecutive(int[] num) {

        Set<Integer> numSet = new HashSet<Integer>();

        for(int i = 0; i < num.length; i++){

            if(!numSet.contains(num[i])){

                numSet.add(num[i]);

            }

        }

        

        int longestLength = 0;

        

        for(int i = 0; i < num.length; i++){

            int currentLength = 0;

            int next = num[i];

            while(numSet.contains(next)){

                numSet.remove(next);

                currentLength++;

                next++;

            }

            

            int previous = num[i] - 1;

            while(numSet.contains(previous)){

                numSet.remove(previous);

                currentLength++;

                previous--;

            }

            longestLength = Math.max(longestLength, currentLength);

        }

        

        return longestLength;

    }

}

再优化,进入循环前就直接判断num[i]在不在set里,不在直接跳过继续!

public class Solution {

    public int longestConsecutive(int[] num) {

        Set<Integer> numSet = new HashSet<Integer>();

        for(int i = 0; i < num.length; i++){

            numSet.add(num[i]);

        }

        

        int longestLength = 0;

        

        for(int i = 0; i < num.length; i++){

            if(!numSet.contains(num[i])){

                continue;

            }

            int currentLength = 0;

            int next = num[i];

            while(numSet.contains(next)){

                numSet.remove(next);

                currentLength++;

                next++;

            }

            

            int previous = num[i] - 1;

            while(numSet.contains(previous)){

                numSet.remove(previous);

                currentLength++;

                previous--;

            }

            longestLength = Math.max(longestLength, currentLength);

        }

        return longestLength;

    }

}

特别警醒的是,开始我的for改成这样,这样如果num[i]不在set里循环就直接退出了,而不是continue。犯了如此基本的错误!

for(int i = 0; i < num.length && numSet.contains(num[i]); i++){

            int currentLength = 0;

            int next = num[i];

            while(numSet.contains(next)){

                numSet.remove(next);

                currentLength++;

                next++;

            }

            

            int previous = num[i] - 1;

            while(numSet.contains(previous)){

                numSet.remove(previous);

                currentLength++;

                previous--;

            }

            longestLength = Math.max(longestLength, currentLength);

        }

 

这就是我的思路。从O(nlogn)到O(n)一般都是这么几个方法。这里使用了空间换时间的思路。

你可能感兴趣的:(sequence)