zoukankan      html  css  js  c++  java
  • [LeetCode] 128. Longest Consecutive Sequence

    [LeetCode] 128. Longest Consecutive Sequence

    题目

    Given an unsorted array of integers, find the length of the longest consecutive elements sequence.Your algorithm should run in O(n) complexity.
    

    样例

    Input: [100, 4, 200, 1, 3, 2]
    Output: 4
    Explanation: The longest consecutive elements sequence is [1, 2, 3, 4]. Therefore its length is 4.
    

    思路一:

    本题要求时间复杂度为 (O(n))。如果进行排序的话,时间复杂度为 (O(n)) 的排序算法有:计数排序,桶排序和基数排序。其中:

    • 计数排序要求数据比较集中,最大值和最小值的差较小。而本题中没有明确数值范围,所以当数值范围为 ([-2^{31} sim 2^{31} - 1]) 时,开辟的计数数组长度为 (2^{32}),复杂度会不一定满足要求。
    • 桶排序要求数据分布比较均匀,从而落在每个桶中的数据个数差不多。题目没没有给出这样的信息。
    • 基数排序要求数据能进行较好的划分,例如对于整数数据而言,它的位数在有限范围内。从而,可以从低位往高位,进行多轮排序。本题中,整数的位数最大为10位,所以最多只需进行10轮排序即可。具体代码如下:
    class Solution {
        public int longestConsecutive(int[] nums) {
            int n = nums.length, index = 0, pos;
            long min = 0;
            Node[] arr = new Node[n];
            Node[] base = new Node[10];
    
            for(int i = 0; i < n; i++){
                if(min > nums[i]){
                    min = nums[i];
                }
            }
            for(int i = 0; i < n; i++){
                arr[i] = new Node(nums[i] - min);
            }
            while(index < n - 1){
                //把每个元素放入桶中,桶中以链表形式存放,以后进先出的形式存放
                for(int i = n - 1; i >= index; i--){
                    pos = (int)(arr[i].cur % 10);
                    arr[i].cur /= 10;
                    arr[i].next = base[pos];
                    base[pos] = arr[i];
                }
                pos = index;
                //从最小值开始回收结点,
                for(int i = 0; i < 10; i++){
                    for(Node cur = base[i]; cur != null; cur = cur.next){
                        arr[pos++] = cur;
                    }
                    //回收结束时,将桶重置为空。便于下一轮使用
                    base[i] = null;
                }
                //回收完成后,更新index
                while(index < n && arr[index].cur == 0){
                    index++;
                }
            }
            //计算连续序列的最大长度
            int max = 0, count = n == 0? 0 : 1;
            for(int i = 1; i < n; i++){
                if(arr[i].val == arr[i - 1].val + 1){
                    count++;
                }
                else if(arr[i].val > arr[i - 1].val){
                    if(max < count){
                        max = count;
                    }
                    count = 1;
                }
            }
            if(max < count){
                max = count;
            }
            return max;
        }
    }
    class Node{
        long cur;
        long val;
        Node next;
        public Node(long val){
            this.cur = val;
            this.val = val;
        }
    }
    

    思路是:

    1. 新建一个 Node 对象数组。将每个数据放入一个 Node 对象中,每个 Node 对象中有三个成员变量:cur, val, next。val 保存数据值。cur 记录每轮记录排序前,数据的当前值,初始为 val。next 保证位于同一个桶中的Node 以链表形式存放。

    2. 每轮排序时,按照上一轮排序结果从大到小的顺序依次取出每个 Node,按照 (Node.cur \% 10) 进行基数排序,同时,将 cur 更新为 (cur / 10),用于下一轮排序。

    3. 对于在相同桶中的节点,后放入的结点放入链表头部,即以后进先出的形式存放。保证同一个桶内的结点,数值大的位于下方。

    4. 按照从小到大的顺序,回收每一个桶。将每个结点放回数组中,从而保证回收后各结点按照前 k 位值递增排列,k 为当前排序的轮数。

    5. 在回收完结点后,从最小值往右遍历 Node,如果 (Node.cur = 0),说明对应数据最多为 k 位整数,那么它的次序已经确定,无须参与后面的基数排序。用 index 记录已确定的元素下标。初始时,index 为0,每轮回收完结点后,当前 index 下标的 Node 处往右遍历,直至 (Node.cur != 0)。那么下一轮排序只需要考虑 ([index ~ n -1]) 中的 Node。

    时间复杂度为:(Theta(n))

    算法实现时的一些细节问题:

    • 基数排序算法的前提是所有数据均为非负数。所以,在代码中先找出最小数据,然后将 (Node.cur) 更新为 (Node.cur - min)。同时,由于 (Node.cur - min) 可能溢出,所以,需要将 (Node.cur) 设置为 long 类型。
    • 输入数据可能为空。需要进行判空处理。
    • 计算连续串最大长度时,输入数据中可能存在相同值,如:2,1,0,1。此时,正确答案是 3,即 0 - 1 - 2.所以相同元素只考虑一次。
    • 计算连续串最大长度时,若 ([i, n - 1]) 是连续串,那么,循环中不会考虑此连续串的长度。需要在循环结束后考虑。
  • 相关阅读:
    网站描述description如何编写
    网站关键词布局设置,这样添加关键词排名很容易上来!
    长尾关键词挖掘工具和使用方法
    小站点如何做好长尾词库(600个长尾词排名的经验分享!)
    如何利用seo技术霸屏你的行业关键词排名
    利用seo技术排名热点新闻词引流(日IP增加2万+)
    yagmail模块的使用
    python--接口自动化
    Python--unittest参数化
    Python--日志模块
  • 原文地址:https://www.cnblogs.com/echie/p/9565487.html
Copyright © 2011-2022 走看看