zoukankan      html  css  js  c++  java
  • 最小可用id

    题目:在非负数组(乱序)中找到最小的可分配的id(从1开始编号),数据量10000000。

    题目解读:在一个不重复的乱序的自然数组中找到最小的缺失的那个数,比如1,2,3,6,4,5,8,11。那么最小可用id就为7。

    代码:

    import java.util.Arrays;
    
    /**
     * 解决最小可用id问题
     */
    public class MinFreeId {
    
        public static void main(String[] args) {
            
    //        int[]arr = {1,5,3,2,6,7,10,9,4};  // 最开始小数据测试
            int []arr = new int[1000*1000];
            for (int i = 0; i < arr.length; i++) {
                // if(i==900000) 那解法一运行时间就太长了
                if (i==90000) {
                    arr[i] = arr.length+10;
                }else {
                    arr[i] = i+1;
                }
            }
            long now = System.currentTimeMillis();
            System.out.println(find1(arr));
            System.out.println("解法一消耗的时间:"+(System.currentTimeMillis()-now)+"ms");
            
            now = System.currentTimeMillis();
            System.out.println(find2(arr));
            System.out.println("解法二消耗的时间:"+(System.currentTimeMillis()-now)+"ms");
            
            now = System.currentTimeMillis();
            System.out.println(find3(arr));
            System.out.println("解法三消耗的时间:"+(System.currentTimeMillis()-now)+"ms");
            
            now = System.currentTimeMillis();
            System.out.println(find4(arr,0,arr.length-1));
            System.out.println("解法四消耗的时间:"+(System.currentTimeMillis()-now)+"ms");
    
        }
        
        // O(n^2) 暴力解法:从1开始依次探测每个自然数是否在数组中
        static int find1(int[]arr){
            int i = 1;
            while(true){
                for (int j = 0; j < arr.length;) {
                    if (arr[j]==i) {
                        i++;
                        j = 0;
                        continue;
                    }else {
                        j++;
                    }
                }
                return i;
            }
        }
        
        // O(nlgn)
        static int find2(int[]arr){
            Arrays.sort(arr);  // O(nlgn)  后续扫描时间O(N) 相比之下 取O(nlgn) 所以时间复杂度为O(nlgn)
            int i = 0;
            while(i<arr.length){
                if (i+1!=arr[i]) {  // 不存在的最小自然数
                    return i+1;
                }
                i++;
            }
            return i+1;
        }
        
        /**
         * 改进1:用辅助空间
         * 有点类似计数排序  O(N)但是浪费空间
         */
        static int find3(int[]arr){
            int n = arr.length;
            int []helper = new int[n+1];
            for (int i = 0; i < n; i++) {  //   O(N)
                if (arr[i]<n+1) {
                    helper[arr[i]] = 1;  // 辅助空间的下标也是有用的
                }
            }
            for (int i = 1; i <= n; i++) {  //   O(N)
                
                if (helper[i] == 0) {
                    return i;
                }
            }
            return n+1;
        }
        
        /**
         * //   O(N)
         * 改进2:分区,递归
         * 问题可转化为:n的正数的数组A,如果存在小于n的数不在数组中,必然存在大于n的数组中,否则数组排列恰好为1到n
         */
        
        private static int find4(int[] arr, int l, int r) {
            if (l>r) {
                return l+1;
            }
            int midIndex = l+((r-l)>>1);  // 中间下标
            int q = SelectK.selectK(arr, l, r, midIndex-l+1);  // 调用查找第k大的元素的方法
            int t = midIndex + 1;  // 期望值
            if (q==t) {  // 左侧紧密
                return find4(arr,midIndex+1,r);
            }else {  // 左侧稀疏
                return find4(arr, l, midIndex-1);
            }
        }
    }

    结果:

      

    结论:根据每个解法所消耗的时间即可得出哪个解法的效率更高。所以在数据量较大的情况下最好选用O(lgn)和O(N)级别的算法,O(nlgn)次之。

  • 相关阅读:
    H5 20-属性选择器上
    H5 19-序选择器下
    H5 18-序选择器
    算法基础部分整理-《图解算法》
    iOS 内存管理之属性关键字
    多线程 ---基础定义部分
    Mongodb基本命令总结
    MySQL四种隔离级别和MVCC
    python同步原语--线程锁
    python进程间通信--信号Signal
  • 原文地址:https://www.cnblogs.com/xiaoyh/p/10275878.html
Copyright © 2011-2022 走看看