二分法


二分法的時間復雜度是O(logn),所以在算法中,比O(n)更優的時間復雜度幾乎只能是O(logn)的二分法。

根據時間復雜渡來倒推算法也是面試中的常用策略:題目中若要求算法的時間復雜度是O(logn),那么這個算法基本上就是二分法。

在這里,我們不做二分法的基本概念介紹,直接給出實現二分最基本的代碼。具體理由看注釋。

在這里特別說明:

在二分法中的while循環只是用於縮小查找范圍,直至縮小到我們能夠直接可辯別的范圍內。而最后結果的return是依靠最后的if語句來比較並實現的。

  1 class solution{
  2 
  3     public:
  4         int binarySearch(int nums[], int target)
  5         {
  6             //判斷傳入的數組不為空
  7             if(nums == NULL || sizeof(nums) / sizeof(int) == 0)
  8             {
  9                 return -1;
 10             }
 11             
 12             int len = sizeof(nums) / sizeof(int);
 13             int start  = 0;
 14             int end = len - 1;
 15             
 16             
 17         //這里判斷條件是start + 1< end
 18         //終止時是start + 1 = end;
 19         //這樣終止時是start和end是相鄰的兩個下標。
 20         
 21         //注意:我們並沒有在while語句里面直接得到並return
 22         //while只是縮小了區間范圍
 23         //而是把范圍縮小到了我們易於操作的兩個索引的范圍內,
 24         //並且通過后面的if語句來判斷並return
 25         while(start + 1 < end)
 26         {
 27             //這里沒有采用middli = (start + end) / 2;
 28             //原因是避免當start和end很大的時候形成溢出
 29             int middle = start + (start - end) / 2;
 30             
 31             if(nums[midddle] == target)
 32             {
 33                 middle = end;
 34             }
 35             else if(nums[middle] < target)
 36             {
 37                 start = middle + 1;
 38             }
 39             
 40             else
 41             {
 42                 end = middle - 1;
 43             }
 44             
 45         }
 46         
 47         if(nums[start] == target)
 48         {
 49             return start;
 50         }
 51         if(nums[end] == target)
 52         {
 53             return end;
 54         }
 55         else
 56         {
 57             return -1;
 58         }
 59             
 60             
 61         }
 62         
 63         int binarySearch_v2(int nums[], int target)
 64         {
 65             if(nums == NULL || sizeof(nums) / sizeof(int) == 0)
 66             {
 67                 return -1;
 68             }
 69             
 70             int len  = sizeof(nums) / sizeof(int);
 71             int start = 0;
 72             int end = len - 1;
 73             
 74             //這里判斷語句是start < end;
 75             //跳出循環時start = end
 76             //所以在后面的if語句判斷中只有nums[start] == target
 77             
 78             //因為int middle = start + (start - end) / 2具有向左靠攏的性質
 79             //所以這里的更新條件為start = middle + 1, end = middle - 1
 80             while(start < end)
 81             {
 82                 int middle = start + (start - end) / 2;
 83                 
 84                 if(nums[middle] == target)
 85                 {
 86                     start = middle;
 87                 }
 88                 else if(nums[middle] < target)
 89                 {
 90                     start = middle + 1;
 91                 }
 92                 else:
 93                 {
 94                     end = middle - 1;
 95                 }
 96             }
 97             
 98             if(nums[start] = target)
 99             {
100                 return start;
101             }
102             else:
103             {
104                 return -1;
105             }
106             
107             
108         }        
109 }

二,二分位置之OOXX

在這種題目中,可以將OO視為不滿足某個條件,而將XX視為滿足某個條件,這樣就可以把一個數組或者序列分為OO....OOXX....XX類型。而這樣的題目往往是給出一個數組,要求找出數組中第一個/最后一個滿足條件的位置。

  OOOOO....OOOXXX...XXXXX

對於這樣的題目可以采用二分法進行。

三:在一個經過排序的數組元素超級多的數組中找出目標元素。

解決這樣的問題,方式一:暴力求解,直接按順序去除數組中元素與目標值target進行比較,這樣的算法的時間復雜度是O(n),當然,在生活中也是不願意看到的。方式二:二分法求解。

我們先來說明c++中vector的實現原理,然后將這樣的原理移植到我們的二分算法中。

 

 三:找出經過旋轉后的排序數組中的最小值

例題:假設一個排好序的數組在其某一未知點發生了旋轉(比如0 1 2 4 5 6 7 可能變成4 5 6 7 0 1 2)。你需要找到其中最小的元素。

所謂旋轉后的排序數組,首先這個數組是經過排序的,數組中所有的元素都是按照一定的順序排列(遞增或者遞減),其次是這個數組經過了旋轉,使得這個數組的排列性質出現了階段性。如圖:

對於這樣的數組,要想找出數組中的最小值,可以直接采用暴力求解,使用for循環進行遍歷,但是這樣的算法的時間復雜度是O(n),並且如果采用這樣的算法也沒什么技術性可言。除了暴力求解,那么就是對這個旋轉后的數組進行二分查找。其時間復雜度是O(logn),其思路如下圖

 

 

 還有一種類型是根據判斷,保留有解的那一半而去掉無解的那一部分。

 

 

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM