アルゴリズム-積み上げ順序、快速列-最小K個数、そして並べ替え出力

26422 ワード

アルゴリズム-積み上げ順序、快速列-最小K個数、そして並べ替え出力
1概要
1.1タイトルの出所
https://leetcode-cn.com/problems/smallest-k-lcci/
1.2テーマの説明
アルゴリズムを設計して,配列の中で最小のk個の数を見つける.このk個の数を任意の順序で返してもいいです.
例:
入力:arr=[1,3,5,7,2,4,6,8],k=4出力:[1,2,3,4]ヒント:
0<=len(arr)<=100000<=k<=min(100000,len(arr))
2構文
2.1トップヒープ
2.1.1問題を解く考え方
  • は、トップヒープを採用し、最小のk個の数を保存する.具体的には、先に前のk個の数を預けて、そして大屋根の規則によって調整します.その後、他の数を遍歴して、より大きな場合は、ツリーをスキップします.より小さい場合は、この要素を置換し、山の頂部から
  • を調整する.
  • は、配列が最小のk個数
  • を保持する順序付けられた大屋根ヒープを得る.
  • は積み重ねられた並べ替えを採用して、その後に並べ替えられた山を出力すればいいです.
    2.1.2コード
    class Solution {
        // 1.     ,    k  
        // 2.             
        public int[] smallestK(int[] arr, int k) {
            if(arr == null || arr.length == 0 || k<=0){
                return new int[0];
            }
            int start;
    
            //      
            int heapSize = arr.length < k ? arr.length : k;
            
            //     
            if(heapSize % 2 == 0){
                start = heapSize/2 - 1;
            }else{
                start = heapSize/2;
            }
    
            //               ,               
            for(; start >= 0; start--){
                adjustMaxHeap(arr, start, heapSize);
            }
    
    
            //             ,   heap+1           ,
            //        ;                   
            if(heapSize<arr.length){
                int tmp = 0;
                for(int i = heapSize;i<arr.length;i++){
                    if(arr[i]<arr[0]){
                        tmp = arr[0];
                        arr[0] = arr[i];
                        arr[i] = tmp;
                        adjustMaxHeap(arr,0,heapSize);
                    }
                }
            }
            
            //       ,          k    ,        k  
            //            :          ,          (         )
            for(int i = 0 ; i < heapSize; i++){
                int tmp = arr[0];
                arr[0] = arr[heapSize-i-1];
                arr[heapSize-i-1] = tmp;
                adjustMaxHeap(arr,0,heapSize-i-1);
            }
    
            //                 ,   
            int[] result = new int[heapSize];
            for(int i = 0; i<heapSize; i++){
                result[i] = arr[i];
            }
            return result;
        }
    
        public void adjustMaxHeap(int arr[], int start, int length){
            if(length<0){
                return;
            }
            //      
            int tmp = arr[start];
            //               ,         
            //                。            ,     
            for(int j = (start+1)*2 -1 ; j<length; j = (start+1)*2 -1 ){
                //       j   
                if(j < length){
                    //          ,              
                    if(j+1 < length){
                        j = arr[j] > arr[j+1] ? j : j + 1;
                    }
                    //              ,            
                    if(tmp > arr[j]){
                        break;
                    }
                    //             
                    arr[start] = arr[j];
                    //                      
                    start = j;
                }
            }
            //     ,start        
            arr[start] = tmp;
        }
    }
    
    2.1.3時間の複雑度
    最適:O(nlogn):最悪:O(nlogn):平均:O(nlogn)
    2.1.4空間の複雑さ
    O(min(n,k)
    2.1.5注意事項Arrays.sort(arr) Arrays.copyOf(arr, k)などの方法を使わないでください.面接官は満足できないです.また、自分で面接をする時、関数名を忘れるかもしれません.
    2.2快速修正
    2.2.1問題を解く構想
    急速な並べ替えの考えを考えると、1つの区切りが見つかります.左と区切り要素を合わせてK個の数があります.最小のk個の数が見つかります.
    満足していない場合は状況に応じて左か右を探し続けます.
    2.2.2コード
    class Solution {
        //         ,         ,
        //           K  ,       k  
        public int[] getLeastNumbers(int[] arrs, int k) {
            //   
            quickSort(arrs, 0, arrs.length-1, k);
            //     k         
            int[] result = new int[k];
            for(int i = 0; i < k; i++){
                result[i] = arrs[i];
            }
            return result;
        }
        //       ,k      k      
        public void quickSort(int[] arrs, int low, int high, int k){
            if(low >= high){
                //             ,    
                return;
            }
            //       
            int tmp = arrs[low];
            int i = low,j=high;
            while(i<j){
                //  high       ,         ,             
                while(i<j&&arrs[j]>tmp){
                    j--;
                }
                if(i<j){
                    //                   ,    i  +1
                    //     j          ,                    
                    arrs[i++] = arrs[j];
                }
                //   ,              ,        
                while(i<j&&arrs[i]<=tmp){
                    i++;
                }
                if(i<j){
                    arrs[j--] = arrs[i];
                }
            }
            //   ,i==j,                            
            //               
            arrs[i] = tmp;
            if(i + 1 - low < k){
                //         k,            k-(i + 1 - low)      ,    
                quickSort(arrs, i+1, high, k-(i + 1 - low));
            } else if(i + 1 - low > k){
                //         k,            k      ,    
                quickSort(arrs, low, i-1, k);
            }
        }
    }
    
    2.2.3時間の複雑度
    最適:O(n)最悪:O(n+n−1+n−2+n−n)=O(n^2(1+n)*n/2)=O(n(n(n−1)/2)=O(n^2)平均:O(n+n/2+n/4+…+1)=O(n)
    2.2.4空間複雑度
    O(1)
    2.2.5注意事項
  • 本のアルゴリズムはデータを全部メモリに読み込む必要があります.使用したい場合は、毎回1つまたは複数のデータを読み込むだけで、要素を区切って比較し、スコアは要素を隔てて小さいファイルに書き込まれます.今度はこの書類を読みに行きます.適当なものが見つかるまで.しかし、このような操作は複数回ディスクで読み書きされ、効率が非常に低いです.
  • 元の配列を変更できない場合、元の配列を追加の空間記憶する必要があります.
  • 2.3分散アルゴリズム
    2.3.1問題を解く考え方
    複数のマシン環境であれば、このタスクを複数のタスクに分割し、各タスクは前のKの大きさを見つけ、最後にもう一度統合して並べ替えると、グローバルの前のKの大きさが分かります.
    2.4ソートアルゴリズム
    2.4.1発泡体の並べ替え
    2.4.1.1問題を解く考え方
    毎回最大の数字を探し出して、K回だけで最大のK個の数を探し出すことができます.
    時間複雑度O(K*N),空間複雑度O(N).
    データを全部読み込む必要がありますが、海量データには適用されません.
    2.4.2交換ソート
    2.4.2.1問題を解く考え方
    一番大きな要素を選ぶたびに、一番前の元素と位置を交換します.K回後に最大のK元素が得られた.
    時間複雑度O(K*N),空間複雑度O(N).
    スペースが足りないなら、毎回1つの数字だけ読み込むことができます.メモリに保存されている最大値と比較します.しかし、この方法は文書K回を読まなければなりません.性能が悪いです.
    参考文献
  • 面接現場–どうやって10億数の中からトップ1000の数を探し出しますか?