[Niuke.com-必見のインタビュートップ 101] 二分探索の質問

目次

二次元配列で検索_NiukeTiba_Niuke.com (nowcoder.com)

Peaks_NiukeTiba_Niuke.com (nowcoder.com) を探しています

array_Niuke Topic_Niuke.com (nowcoder.com) 内の逆順序ペア

回転配列の最小数_NiukeTiba_Niuke.com (nowcoder.com)


 

二次元配列で検索_NiukeTiba_Niuke.com (nowcoder.com)

質問の意味:

2 次元配列 (各 1 次元配列は同じ長さ) では、各行は左から右に昇順に並べ替えられ、各列は上から下に昇順に並べ替えられます。関数を完成させ、二次元配列と整数を入力し、配列に整数が含まれているかどうかを判定してください。

[

[1,2,8,9]、
[2,4,9,12]、
[4,7,10,13]、
[6,8,11,15]

]

target = 7 の場合、true を返します。

target = 3 の場合、false を返します。

データ範囲:行列の長さと幅は0≤n,m≤5000を満たし、行列内の値は0≤val≤10^9を満たす
アドバンスト:空間計算量O(1)、時間計算量O(n+ m)

[入力例] 7,[[1,2,8,9],[2,4,9,12],[4,7,10,13],[6,8,11,15]]

[出力サンプル] true

問題解決のアイデア:

マトリックスのルールは、左から右、上から下に増加することです。

比較のために行列の右上隅にある a[row][col] を選択します。target<a[row][col] の場合、ターゲットが現在の列の左側にあることが証明され、それを見つけるには左行列。

target>a[row][col] の場合、ターゲットが現在の行の下にあることが証明され、以下の行列内を検索します。

import java.util.*;


public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param target int整型 
     * @param array int整型二维数组 
     * @return bool布尔型
     */
    public boolean Find (int target, int[][] array) {
        // write code here
        int n = array.length;
        int m = array[0].length;
        int row = 0;//行
        int col = m-1;//列
        while(row < n && col >= 0){
            if(target == array[row][col]){
                return true;
            }else if(target > array[row][col]){
                row++;
            }else{
                col--;
            }
        }
    
        return false;
    }
}

Peaks_NiukeTiba_Niuke.com (nowcoder.com) を探しています

質問の意味:

長さ n の配列 nums を指定すると、ピーク値を見つけてそのインデックスを返します。配列には複数のピークが含まれる場合がありますが、その場合はいずれかのピークの位置を返すだけです。

1. ピーク要素とは、その値が左右の隣接する値よりも厳密に大きい要素を指します。厳密に以上

2. nums[-1] = nums[n] = −∞と仮定します。

3. すべての有効な i に対して、nums[i] != nums[i + 1] があります。

4. この問題を O(logN) 時間計算量で実装できますか?

データ範囲:

1≤数値.長さ≤2×105 

−231<=nums[i]<=231−1

 入力例:[2,4,1,2,7,8,4]

出力サンプル: 1

 問題解決のアイデア:

1. 激しい列挙。前の桁より大きく、次の桁よりも大きい限り、それがピーク値であり、直接返されます。

import java.util.*;


public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param nums int整型一维数组 
     * @return int整型
     */
    public int findPeakElement (int[] nums) {
        // write code here
        if(nums.length >= 2 && nums[0] > nums[1] || nums.length == 1){
            return 0;
        }
        if(nums.length >= 2 && nums[nums.length-2] < nums[nums.length-1]){
            return nums.length-1;
        }
        for(int i=1;i<nums.length-1;++i){
            if(nums[i] > nums[i-1] && nums[i] > nums[i+1]){
                return i;
            }
        }
        return -1;
    }
}

解決策のアイデア 2:

二分探索、実装時間の計算量は O(Logn)

通常の二分探索と同様に、mid が最初に計算されます。

nums[mid] > num[mid+1] の場合、mid がピーク値である可能性が高いことを意味するので、左に進みます。ここでの二分探索との違いは、左に進む場合、右 =mid、中間は可能であるため、中間 1 ではありません。ピーク値は次の巡回ラウンドで比較する必要があります。

nums[mid] <= nums[mid+1] の場合、mid+1 がピーク値である可能性が高いことを意味します。mid はピーク値の可能性がなくなったため、右、左 = Mid+1 に移動します。だから含めないでください

複数回のトラバースの後、最終的に間隔内で正しいピーク値を見つけることができます。

単調増加の場合は、left=right=nums.length-1 になるまで毎回右に移動し、単調減少の場合は、left=right=0 まで左に移動します。

import java.util.*;


public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param nums int整型一维数组 
     * @return int整型
     */
    public int findPeakElement (int[] nums) {
        // write code here
       if(nums.length == 1){
           return 0;
       }
       int left = 0;
       int right = nums.length -1;
       int mid;
       while(left < right){
            mid = (left + right) /2;
            if(nums[mid] > nums[mid+1]){
                //mid比下一位大,有可能是山峰,往左遍历
                right = mid;//注意这里right是赋值mid,因为mid可能是山峰,所以要包含他去寻找
            }else{
                //mid比它下一位小,mid+1有可能是山峰,向右走
                left = mid + 1;//从大的数开始往右查找
            }
       }
        return right;
    }
}

array_Niuke Topic_Niuke.com (nowcoder.com) 内の逆順序ペア

トピックの説明:

配列内の 2 つの数値で、最初の数値が後の数値より大きい場合、2 つの数値は逆順のペアを形成します。配列を入力し、配列内の逆順ペアの総数 P を求めます。そして、P モジュロ 1000000007 の結果を出力します。つまり、出力 P mod 1000000007


データ範囲: データの 50% の場合、サイズ ≤10^4
データの 100% の場合、サイズ ≤10^5

配列内のすべての数値の値は 0≤val≤10^9 を満たします
 

要件: 空間計算量 O(n)、時間計算量 O(nlogn)

【入力例】[1,2,3,4,5,6,7,0]

【出力サンプル】7

問題解決のアイデア 1: 二重ループ、暴力的な列挙、時間計算量は O(n^2)、実行タイムアウト 

import java.util.*;


public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param nums int整型一维数组 
     * @return int整型
     */
    public int InversePairs (int[] nums) {
        // write code here
        int ans=0;
        for(int i =0; i<nums.length-1; ++i){
            for(int j=i; j< nums.length; ++j){
                if(nums[i] > nums[j]){
                    ans++;
                    ans %= 1000000007;
                } 
            }
        }
        return ans;
    }
}

解決策のアイデア 2:

 マージソート方法に基づいて、マージ中に、右側の数が左側の数より小さい場合、現在生成されている逆順ペアの数を直接計算できます。

import java.util.*;


public class Solution {
    int ans=0;
    public int InversePairs (int[] nums) {
        // write code here
        if(nums.length < 2){
            return 0;
        }
        mergeSort(nums,0,nums.length-1);
        return ans;
    }
    public void mergeSort(int[] nums,int left,int right){
        //分割点
        int mid = (left+right)/2;
        if(left < right){
            mergeSort(nums,left,mid);
            mergeSort(nums,mid+1,right);
            //合并
            merge(nums,left,mid,right);
        }
    }
    public void merge(int[] nums,int left,int mid,int right){
        //创建临时数组
        int[] arr = new int[right - left + 1];
        //临时数组下标起点
        int c = 0;
        int s = left;
        int l = left;
        int r = mid + 1;//左右数组的起始指针
        while(l <= mid && r <= right){
            //当左数组的元素小时,跳过
            if(nums[l] <= nums[r]){
                //放入临时数组
                arr[c] = nums[l];
                c++;
                l++;
            }else{
                //存在逆序对,统计
                arr[c] = nums[r];
                //逆序对个数,
                ans += mid+1 - l;
                ans %= 1000000007;
                c++;
                r++;
            }
        }
        //左子数组还有元素,放入
        while(l <= mid){
            arr[c++] = nums[l++];
        }
        while(r <= right){
            arr[c++] = nums[r++];
        }
        //临时数组放入数组原位置
        for(int num: arr){
            nums[s++] = num;
        }
    }
}

回転配列の最小数_NiukeTiba_Niuke.com (nowcoder.com)

トピックの説明:

[1,2,3,4,5] など、長さ n の非降順配列があります。これを回転します。つまり、配列の最初の要素を配列の末尾に移動して、回転された配列にします。たとえば、[3,4,5,1,2]、または [4,5,1,2,3] になります。このような回転された配列が与えられた場合に、配列内の最小値を見つけてください。

データ範囲: 1≤n≤10000、配列内の任意の要素の値: 0≤val≤10000

要件: 空間計算量: O(1)、時間計算量: O(logn)

【入力例】[3,4,5,1,2]

【出力サンプル】1 

問題解決のアイデア:

非降順配列を回転するには、二分探索を使用して配列を 2 つのサブ配列に分割します。順序が正しくないサブ配列が 1 つ存在する必要があります。

たとえば、[left, right] は [left, middle] [mid, right] に分割されます。nums[left] > nums[mid] の場合、[left, middle] 間隔が a の要件を満たしていないことがわかります。非降順配列なので、この間隔は回転後に無秩序になり、最小値がここで見つかります。

等しい場合は範囲​​を狭めて検索を続けます。

import java.util.*;


public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param nums int整型一维数组 
     * @return int整型
     */
    public int minNumberInRotateArray (int[] nums) {
        // write code here
        int left = 0;
        int right = nums.length-1;
        while(left < right){
            int mid = (left + right) / 2;
            if(nums[mid] > nums[right]){ //右子数组无序
                left = mid + 1;
            }else if(nums[mid] < nums[right]){//左子数组无序
                right = mid;
            }else{
                //如果是相等的话,缩小范围
                right--;
            }
        }
        return nums[left];
    }
}

 

おすすめ

転載: blog.csdn.net/qq_37998848/article/details/133499885