题目
思路
参考题解 主要参考的三叶姐的题解以及其他几个题解的延伸
二分搜索练习参考
搜索旋转排序数组 1、2
容易理解的思路是根据 旋转排序数组的二段性,画图可知
主要思路:
1、(有重复元素先恢复二段性)找到二段性分割点 也就是找到满足>=nums[0]的最大值
2、此时right就是分割点的index 判断target到底在哪边进行二分查找
代码1
代码2
153. 寻找旋转排序数组中的最小值
方法一、与nums[right]比较
代码
int findMin(vector<int>& nums) {
int n=nums.size();
int left=0,right=n-1;
//画图理解二分性
while(left<right){
int mid=left+(right-left)/2;
//只有1个数字的时候nums[mid]==nums[right] 此时已经退出
if(nums[mid]>nums[right]){
//说明min在mid右侧
left=mid+1;
}else if(nums[mid]<nums[right]){
//说明min在mid左侧 或者就是min
right=mid;
}
}
return nums[left];
}
方法二、与nums[0]比较 找到旋转点 根据旋转点返回最小值
int findMin(vector<int>& nums) {
int n=nums.size();
int left=0,right=n-1;
//找到>=nums[0]的最大的值
while(left<right){
int mid=left+right+1>>1;
if(nums[mid]>=nums[0]){
left=mid;
}else{
right=mid-1;
}
}
return nums[(right+1)%n];
}
154. 寻找旋转排序数组中的最小值 II
方法一、先恢复二段性 然后找到旋转点 最后得到最小值
int findMin(vector<int>& nums) {
//恢复二段性
int n=nums.size();
int left=0,right=n-1;
while(left<right && nums[right]==nums[0]){
right--;
}
//得到了新的right 恢复了二段性
//找到旋转点
while (left<right){
int mid=left+right+1>>1;
if(nums[mid]>=nums[0]){
left=mid;
} else{
right=mid-1;
}
}
return nums[(right+1)%n];
}
方法二、类似上一题的思路,
尝试先恢复二段性 然后利用与nums[right]的关系找到最小值
int findMin(vector<int>& nums) {
//恢复二段性
int n=nums.size();
int left=0,right=n-1;
while(left<right && nums[right]==nums[0]){
right--;
}
//得到了新的right 恢复了二段性
//根据和nums[right]二分搜索
while (left<right){
int mid=left+(right-left)/2;
if(nums[mid]>nums[right]){
left=mid+1;
}else{
right=mid;
}
}
return nums[right];
}
34. 在排序数组中查找元素的第一个和最后一个位置
关于二分搜索的细节问题
nums[mid]<=target 符合条件的就是前面的一段
然后我们最终找到的必然是这一段的右端点(因为它相对于左端点 必然更接近中心) 也就是最后一个 8
而有没有 +1 取决于 我们在 check 条件为 true 的时候 修改的是不是 left 指针 如果是的话 就要 + 1
这是为了防止下取整导致的死循环