二分法的時間復雜度是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),其思路如下圖
還有一種類型是根據判斷,保留有解的那一半而去掉無解的那一部分。