本人最近一直在作一些算法方面的學習,最近也刷了一些力扣題目,我將我作過的題目分享到了個人GitHub上:算法題解能夠供你們參考。最近在刷題的過程中,我發現我總是在二分法的邊界條件上出問題,常常是出現棧溢出的狀況。因此想寫一篇文章,記錄一下個人學習心得與體會。java
二分法每每是對一個有序的數據形式,進行查找特定值target的算法。git
該算法的優點是時間複雜度僅爲O(log n),相較於順序查找O(n)的時間複雜度有着明顯的提高。github
二分法有4個重要的值:target,start, end, mid.算法
我將二分法的區間劃分,分爲3鍾類型:數組
劃分爲[start,mid]和[mid+1,end]這兩個區間函數
劃分爲[start,mid-1]和[mid,end]這兩個區間學習
劃分爲[start,mid-1]和mid和[mid+1,end]這三個區間code
這三種分法的區別就是: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]這樣兩個區間。
之後碰到這種狀況,牢記分開元素準則,咱們只須要當場覆盤一下這個過程便可避免棧溢出的產生!