Leetcode 0004:2つのソートされた配列の中央値

タイトル説明:

サイズがそれぞれmとnの2つのソートされた配列nums1とnums2が与えられた場合、2つのソートされた配列の中央値を返します。
フォローアップ:全体的な実行時の複雑さはO(log(m + n))である必要があります。

例1:

入力:nums1 = [1,3]、nums2 = [2]
出力:2.00000
説明:マージされた配列= [1,2,3]で、中央値は2です。

例2:

入力:nums1 = [1,2]、nums2 = [3,4]
出力:2.50000
説明:マージされた配列= [1,2,3,4]で、中央値は(2 + 3)/ 2 = 2.5です。

例3:

入力:nums1 = [0,0]、nums2 = [0,0]
出力:0.00000

例4:

入力:nums1 = []、nums2 = [1]
出力:1.00000

例5:

入力:nums1 = [2]、nums2 = []
出力:2.00000

制約:

nums1.length == m
nums2.length == n
0 <= m <= 1000
0 <= n <= 1000
1 <= m + n <= 2000
-106 <= nums1 [i]、nums2 [i] <= 106

時間計算量:O(log(m + n))
二分探索二分法:
2つの順序付けられた配列が与えられた場合、中央値(n + m)/ 2を見つけます。これは、k番目に小さい要素k =(n + m)を見つけることと同じです。 )/ 2

  1. 全長lenが偶数の場合、中央値はlen / 2番目に小さい数とlen / 2 +1番目に小さい数の平均です。
  2. 全長lenが奇数の場合、中央値はlen / 2 +1番目に小さい数です。

問題は、2つの順序付けられた配列でk番目に小さい数を見つける方法です。最初に、nums1とnums2から最初のk / 2要素を取得します。

  1. 最初の配列nums1のk / 2番目の小数が2番目の配列nums2のk / 2番目の小数よりも大きい場合、つまり、nums1 [k / 2-2-1]> nums2 [k / 2-1]です。これは、nums2の最初のk / 2要素がk番目に小さい数よりも小さくなければならないことを意味します。したがって、最初にこれらの数値を取り出してから、残りの数値でk−⌊k /2⌋の小数を見つけることができます。
  2. 同様に、最初の配列nums1のk / 2番目の小数が2番目の配列nums2のk / 2番目の小数よりも小さい場合、つまり、nums1 [k / 2-1-1] <nums2 [k / 2-1]です。これは、nums1の最初のk / 2要素がk番目に小さい数よりも小さくなければならないことを意味します。したがって、最初にこれらの数値を取り出してから、残りの数値でk−⌊k /2⌋の小数を見つけることができます。

境界条件を考慮してください。

  1. たとえば、配列の全長がk / 2未満の場合、nums1の長さはn <k / 2です。各配列の有効長のペアと配列nums1(開始点)の有効長を考慮する必要があります。はi)有効長si = Math.min(nums1.length、i + k / 2);
    配列nums2有効長(開始点はj)sj = j + k-k / 2。
  2. nums1 [si-1]> nums2 [sj-1]の場合、k番目に小さいターゲット数が[i、n]と[sj、m]にある必要があることを意味します。
  3. nums1 [si-1] <= nums2 [sj-1]の場合、ターゲットのk番目に小さい数が[si、n]および[j、m]にある必要があることを意味します。
class Solution {
    
    
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
    
    
        int len = nums1.length + nums2.length;
        if(len%2 == 0){
    
    
            int left = find(nums1, 0, nums2, 0, len/2);
            int right = find(nums1, 0, nums2, 0, len/2+1);
            return (left+right)/2.0;
        }else{
    
    
            return (double)find(nums1, 0, nums2, 0, len/2+1);
        }
    }
    
    int find(int[] nums1, int i, int[] nums2, int j, int k){
    
    
        //默认第一个是小的
        if(nums1.length - i > nums2.length-j){
    
    
            return find(nums2, j, nums1, i, k);
        }
        if(nums1.length == i){
    
    
            return nums2[j+k-1];
        }
        //当取第1个元素
        if(k == 1) return Math.min(nums1[i],nums2[j]);
        int si = Math.min(nums1.length, i+k/2);
        int sj = j+k-k/2;
        if(nums1[si-1] > nums2[sj-1]){
    
    
            return find(nums1, i, nums2, sj, k-(sj-j));
        }else{
    
    
            return find(nums1, si, nums2, j, k-(si-i));
        }
    }
}

おすすめ

転載: blog.csdn.net/weixin_43946031/article/details/113781099