第一题
由题意可知,最左边和最右边的数是负无穷,所以我们进行设置mid中点,观察有下面两种情况:
当出现第一种情况时,中点和其后一位构成下降区域,由于数组左右两侧是负无穷,所以mid左边一定有一个峰值,但是mid右侧可能不一定有峰值;
当出现第二种情况时,中点和其后一位构成上升区域,由于数组左右两侧是负无穷,所以mid右边一定有一个峰值,但是mid左侧可能不一定有峰值;
解题思路如下:
由于二段性,可以使用二分法:
情况一:下降区域,峰值在mid左边,右指针移到mid;
情况二:上升区域,峰值在mid右边,右指针移到mid+1;
代码如下:
class Solution { public int findPeakElement(int[] nums) { int left = 0,right = nums.length-1; while(left < right) { int mid = left + (right-left)/2; if(nums[mid] < nums[mid+1]){ left= mid+1; }else{ right = mid; } } return left; } }
第二题
由题意可知:
经过旋转之后所有的数都满足一下规律:
其中a到b是已经被旋转之后的数字,c到d之间的数字是未被旋转的数字;
选择判断值,即d点所表示的数,nums【n-1】,旋转前的数字都小于该数,旋转后的数值都大于该数;
由此我们可以分析解题思路:
mid所指向的数,要是在ab区间,则左指针指向mid+1的位置;要是指向cd区间,则右指针指向mid位置(因为mid所指向的值有可能就是我们需要返回的数字);
代码如下:
class Solution { public int findMin(int[] nums) { int left= 0,right = nums.length - 1; int t = nums[right]; while(left < right){ int mid = left+(right-left)/2; if(nums[mid] > t){ left = mid+1; }else{ right = mid; } } return nums[left] ; } }
第三题
由上述题意可知, 如下图所示,整个数组区域可以分为两个区域:
假设如上所示,缺少下标为3的数,则该数之前的下标和该位置所指的数值一样大;
同时3下标右边的数值和其对应的位置的数值不一样,由此二段性,我们可以采用二分法:
其中解题原理如下图所示,详细步骤如上题故事:
本题的细节问题,当我们所缺的元素是最后一个是,我们当前的循环代码是判断不出来的,所以当上述循环结束后返回的下标值如果和该下标所指的数的值一样大的话,则返回值应该是将改下标值加一,反之则返回上述循环结束后得到的下标值;
综合上诉,代码如下:
class Solution { public int takeAttendance(int[] records) { int left=0 ,right= records.length-1; while(left< right){ int mid = left + (right - left)/2; if(records[mid] == mid){ left = mid + 1; }else{ right = mid; } } //处理细节问题 return records[left] == left?left +1 :left; } }
ps:关于二分法的内容就到这里了,如果大家感兴趣的话就请一键三连哦!!!