對於二分法的一些感想

前言

​ 本人最近一直在作一些算法方面的學習,最近也刷了一些力扣題目,我將我作過的題目分享到了個人GitHub上:算法題解能夠供你們參考。最近在刷題的過程中,我發現我總是在二分法的邊界條件上出問題,常常是出現棧溢出的狀況。因此想寫一篇文章,記錄一下個人學習心得與體會。java

二分法用來幹嗎

二分法每每是對一個有序的數據形式,進行查找特定值target的算法。git

​ 該算法的優點是時間複雜度僅爲O(log n),相較於順序查找O(n)的時間複雜度有着明顯的提高。github

二分法的分類

​ 二分法有4個重要的值:target,start, end, mid.算法

​ 我將二分法的區間劃分,分爲3鍾類型:數組

  1. 劃分爲[start,mid]和[mid+1,end]這兩個區間函數

    無標題

  2. 劃分爲[start,mid-1]和[mid,end]這兩個區間學習

    無標題1

  3. 劃分爲[start,mid-1]和mid和[mid+1,end]這三個區間code

    無標題3

    ​ 這三種分法的區別就是:mid該放在哪裏排序

    ​ 該如何劃分區間,是得視具體狀況進行的。有的經典二分徹底可使用第三種分法(我的最喜歡的,由於邊界條件最簡單),可是有的時候,必須得用第一種和第二種形式,如:力扣第35題 。這題須要將mid歸到左區間當中。(start<target <= mid)。leetcode

邊界條件的難點

​ 狀況3邊界條件比較簡單,當(start>end)的時候跳出循環便可,不會形成死循環或者棧溢出。可是狀況2和狀況3每每會形成邊界條件分析不清晰致使產生死循環!

​ 爲何說邊界條件難呢?若是mid值取得不對,容易形成死循環。且形成死循環每每是在剩下兩個值的時候產生。這裏舉個例子:

在條件2的時候,下面的代碼就會形成死循環!!!!

//在狀況2的時候,該代碼會形成死循環!!!
//假設array是從小到大排序的有序數組
static int BinarySearch(int[] array,int target,int start,int end){
    if(target < array[start] || target > array[end]) return -1;
    if(start == end){
        if(array[start] == target) return start;
        else return -1;
    }
    int mid = (start + end) / 2;
    if(array[mid] <= target)
        return BinarySearch(array,target,mid,end);
    else
        return BinarySearch(array,target,start,mid-1);
}

主函數爲:

public static void main(String[] args) {
        int[] array = {0,2};
        int re = BinarySearch(array,0,0,1);
    	System.out.println(re);
    }

報錯爲:

Exception in thread "main" java.lang.StackOverflowError
	at demo.BinarySearch(demo.java:14)
	at demo.BinarySearch(demo.java:14)
	at demo.BinarySearch(demo.java:14)
	at demo.BinarySearch(demo.java:14)

可是咱們將代碼換成第一種狀況,即:將第一個條件的 <= 變爲 < 並將區間變化修改爲第一種狀況,將會是正確的!

//在狀況1的時候,代碼會成功運行!!!
//假設array是從小到大排序的有序數組
static int BinarySearch(int[] array,int target,int start,int end){
    if(target < array[start] || target > array[end]) return -1;
    if(start == end){
        if(array[start] == target) return start;
        else return -1;
    }
    int mid = (start + end) / 2;
    //將這裏的<=該成<,並修改區間
    if(array[mid] < target)
        return BinarySearch(array,target,mid+1,end);
    else
        return BinarySearch(array,target,start,mid);
}

一樣用第一個主函數跑,結果是正確的!

0

Process finished with exit code 0

我以前在這裏總是理解很糊塗,走了很多彎路。可是,如今我不再會在這裏栽跟頭了!!!!

解決邊界條件

​ 你們也看見了,我數組會形成棧溢出,說明,這裏的邊界條件致使的棧溢出就是在數組剩下兩個元素的時候發現。爲何會發生這樣的狀況其實能夠這樣區分:當只剩下兩個元素的時候,用mid能不能使得這兩個元素分開!

看第一個會形成死循環的例子:

​ 當數組是[left,left+1]這種狀況的時候,mid的值爲left,這時候,劃分爲[left,left-1]和[left,left+1]這兩個區間,這樣兩個區間,沒辦法將left和left+1這兩個元素分開,說明這樣的mid是沒有意義的。

​ 這時候咱們須要將mid = mid+1即mid = left + 1可分開!由於這樣,區間能夠劃分爲[left,left]和[left+1,left+1]這樣兩個區間。這樣才能將兩個元素分開。

​ 而針對狀況1,mid的值爲left就能夠分開,這時候,劃分爲[left,left]和[left+1,left+1]這樣兩個區間。

​ 之後碰到這種狀況,牢記分開元素準則,咱們只須要當場覆盤一下這個過程便可避免棧溢出的產生!

相關文章
相關標籤/搜索