超基本アルゴリズム:二分探索法

前書き

二分法は、5つの基本アルゴリズムの中で分割統治アルゴリズムの1つです。二分法の考え方によれば、二分法の考え方は非常に単純です。

  1. 間隔を2つの部分に分割し、検索要素が属する部分を決定します。
  2. 間隔を更新して、最初のステップを繰り返します。間隔が1つの要素のみに短縮されるまで。

二分探索法は、実際の使用において比較的大きな制限があります。二分探索法は、次の要件に準拠する必要があります。

  1. 配列やリンクリストなどのシーケンシャルストレージ構造を使用する必要があります収集は認められません。
  2. 順番に並べる必要があります。つまり、保管時に順番に並べます。

例えば

例:10桁の配列。aからzまでの10文字を順に格納します。これには文字xが含まれます。二分法に従って文字xを見つけます。

a c d f j l q バツ

まず、配列の中央で要素jを見つけます(jまたはlは問題ありませんが、jを例にとります)。jはxより小さく、要素は配列に順番に格納されます。次に、xはjとzの間にある必要があります。

  1. jとzの間の要素nを取り、nはまだxより小さい。
  2. nとzの間の要素qを取り、qはxより小さい。
  3. q〜zの真ん中にある要素を取り、xを見つけます。

上記は、バイナリ検索の簡単な例です。コード実装を使用する場合は、再帰を使用する必要があります。困難は次のとおりです。

  • 終了条件を決定する方法。
  • 中央値が2つある場合は、どちらを採用するか。
  • 最後の間隔に2つの要素しかない場合に正しい値を取得する方法。

応用

次に例を示します。

重複の数を見つける:

n + 1の整数を含む配列numがあり、その数がすべて1〜n(1とnを含む)の場合、少なくとも1つの整数が繰り返されることがわかります。繰り返される整数が1つしかないと仮定して、繰り返される数を見つけます。

例1:

输入: [1,3,4,2,2]
输出: 2

ソース:LeetCode
リンク:元のタイトルリンク

アイデア:

タイトルから次の条件を抽出できます。

  • 繰り返される数は1つだけです。
  • すべての数値はnの範囲です。
  • 合計n + 1個の要素があります。

質問は、繰り返される要素の値を見つけることだけを必要とし、要素の位置を気にしないので、二分法を使用してそれを見つけることができます。

すべての要素は1からnの間であり、1つの要素のみが繰り返されるため、そのような繰り返し数がないと仮定すると、この配列のn / 2未満の要素の数は、n / 2より大きい要素の数と同じになります。 。この数値を加算すると、バランスが崩れ、n / 2より大きい間隔に属するか、n / 2より小さい間隔に属するかを判断できます。

これをキーとして繰り返し、最後にこの繰り返された要素の値を取得します。

コード:

package leetcode;


public class FindDuplicate {
    int num = 0;
    public int findDuplicate(int[] nums) {
        int minLine = 1;
        int maxLine = nums.length-1;
        dichotomySearch(minLine,maxLine,nums);
        return num;
    }

    public void dichotomySearch(int minLine,int maxLine,int[] nums) {
        int flag = 0;
        int median = (minLine + maxLine)/2;

        //only two number
        if(minLine==maxLine-1||minLine==maxLine){
            for (int i = 0; i < nums.length; i++) {
                if (nums[i]==minLine){
                    flag++;
                }
            }
            if (flag>1){
                num = minLine;
            }else {
                num = maxLine;
            }
            return;
        }
        for (int i = 0; i < nums.length; i++) {
            if (nums[i] < median && nums[i]>=minLine){
                flag--;
            }
            if (nums[i] > median && nums[i]<=maxLine){
                flag++;
            }
        }
        if (flag<=0){
            maxLine = median;
            dichotomySearch(minLine,maxLine,nums);
        }else {
            minLine = median;
            dichotomySearch(minLine,maxLine,nums);
        }
    }

    public static void main(String[] args) {
        int[] nums =  {1,1};
        FindDuplicate findDuplicate = new FindDuplicate();
        System.out.println(findDuplicate.findDuplicate(nums));
    }
}

 

おすすめ

転載: blog.csdn.net/x950913/article/details/106361889