classSolution { public: intfindPeakElement(vector<int>& nums){ int l = 0, r = nums.size()-1; while(l <= r){ int m = (l + r) / 2; if(m-1>=0 && nums[m-1]>nums[m]) r = m - 1; elseif(m+1<nums.size() && nums[m+1]>nums[m]) l = m + 1; else return m; } return0; // 永远不会走 } };
1.2 二分法(优雅)
其实只要搞清楚我们「二分」什么内容,根本不会存在说用哪种方式才能写过的情况。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
classSolution { public: intfindPeakElement(vector<int>& nums){ int l = 0, r = nums.size()-1; while(l < r){ int m = (l + r) >> 1; // 这里m+1不会越界,因为l <= m < r,所以m-1是可能越界的,m+1必然不会越界 if(nums[m] > nums[m+1]) r = m; // 注意 else l = m + 1; // 注意 } return l; } };
classSolution { public: intsearch(vector<int>& nums, int target){ int n = nums.size(), l = 0, r = n - 1; while(l <= r){ int m = (l + r) >> 1; if(nums[m] == target) return m; if(nums[l] <= nums[m]){ // 左边正常 if(target >= nums[l] && target < nums[m]) r = m - 1; else l = m + 1; } else{ // 右边正常 if(target > nums[m] && target <= nums[r]) l = m + 1; else r = m - 1; } } return-1; } };
// while等号和不等号 classSolution { public: intsearch(const vectorr<int>& arr, int target){ int l = 0, r = arr.size() - 1; while(l < r){ int m = (l+r)/2; if(arr[m] == target) return m; if(arr[m] < arr[r]){ // 右边正常(互不相同所以没等于) if(target > arr[m] && target<=arr[r]) l = m + 1; else r = m - 1; }else{ // 左边正常 if(target >= arr[l] && target<arr[m]) r = m - 1; else l = m + 1; } } return arr[l] == target ? l : -1; } };
classSolution { public: intsearch(vector<int>& arr, int target){ int l = 0, r = arr.size() - 1; while(l <= r){ int m = (l+r)/2; if(arr[m] == target) return m; if(arr[m] < arr[r]){ // 右边正常(互不相同所以没等于) if(target > arr[m] && target<=arr[r]) l = m + 1; else r = m - 1; }else{ // 左边正常 if(target >= arr[l] && target<arr[m]) r = m - 1; else l = m + 1; } } return-1; } };
不能动不动l = m + 1,r = m - 1这种大起大和的方式,因为目的是求极值而不是target,target不等于的时候,某一边确实可以跳;但是求极值时,例如下面代码中r = m,因为不确定nums[m]是不是极值,所以不能写成r = m - 1
1 2 3 4 5 6 7 8 9 10 11 12 13 14
classSolution { public: intfindMin(vector<int>& nums){ int l = 0, r = nums.size()-1; while(l < r){ int m = (l + r) / 2; if(nums[m] < nums[r]) r = m; // 注意 else l = m + 1; // 注意 } return nums[l]; } };
classSolution { public: intfindMin(vector<int>& arr){ int l = 0, r = arr.size()-1; while(l < r){ int m = (l + r) / 2; if(arr[m] < arr[r]) r = m; elseif(arr[m] > arr[r]) l = m + 1; else --r; } return arr[l]; } };