ソードフィンガーオファーインタビュー質問51:配列内の逆ペア

この質問をするとき、最初に頭に浮かぶのは、前から後ろに1つずつトラバースして、逆のペアを見つけることです。時間計算量はn ^ 2であり、絶対に通過しません。

その後、逆順の関係が数値の大きさに関係し、ソートで実行できることが発見されましたが、ソートに問題があります。つまり、数値の位置を変更した後、その後の数値の計算でほとんど実現されていません。

 

答えを読んだ後、この問題の答えは、配列を長さ1の隣接する配列に分割することです。隣接する配列については、サイズを決定し、逆の順序を数えて、それらをマージします。これらの2つの数値以外の逆の順序で他の統計値に影響を与えることはないため、2つの数値が並べ替えられてから、マージされた配列が再帰的にマージされ、ペアで並べ替えられます。

 

応答コード、コピー配列、およびデータ配列の再帰呼び出しは、1回再帰的に行われ、1回交換されるため、理解するのが困難です。

各レイヤーはデータ内のデータを操作してコピーにマージするため、再帰中の代替呼び出しは、現在の関数によって呼び出されたデータがサブ再帰コピーであり、マージされたサブ再帰コピーが後に取得されることを意味しますサブ再帰コピー。データは親の再帰データとして使用され、次に子の再帰データは、計算を通じて親の再帰コピー配列の値を格納するためのコンテナーとして使用されます。

 

    public int reversePairs(int[] nums) {
        if(nums.length == 0){
            return 0;
        }  
        int[] copy = new int[nums.length];
        for(int count = 0;count<nums.length;count++){
            copy[count] = nums[count];
        }

        int res = reversePairsDivide(nums,copy,0,nums.length-1);
        return res;
    
    }
    public int reversePairsDivide(int[] data,int[] copy,int start,int end) {
        if(start == end){
            return 0;
        }
        int data_length = end - start;
        int mid = data_length/2;
        int left = reversePairsDivide(copy,data,start,start+mid);
        int right = reversePairsDivide(copy,data,start+mid+1,end);
        int i = start + mid;
        int j = end;
        int copyIndex = end;
        int res = 0;
        while(i>= start&& j>=start + mid + 1){
            if(data[i]>data[j]){
                res += (j - start - mid);
                copy[copyIndex--] = data[i--];
            }else{
                copy[copyIndex--] = data[j--];
                
            }
        }

        for(;i>=start;){
            copy[copyIndex--] = data[i--];
        }

        for(;j>=start + mid + 1;){
            copy[copyIndex--] = data[j--];
        }
        return res + left + right;
    }

 

おすすめ

転載: blog.csdn.net/qq_40473204/article/details/114636518