题目
思路
- 此题的关键在于,需要清楚,左边的和右边的,哪边是可以放弃的。
- 如果
nums[mid] < nums[right]
,说明[mid, right]
必然有序 - 如果
nums[mid] > nums[right]
,说明[left, mid - 1
]必然有序 - 利用有序区间的端点值,判断是不是在序列当中,如果在,那么放弃掉无序的一边,如果不在,放弃掉有序的一边。
此题的二段性,体现在,一段里面包含target,另外一段不包含target
代码
class Solution {
public:
int search(vector<int>& nums, int target) {
// 如果 nums[mid] < nums[right],说明[mid, right]必然有序
// 如果 nums[mid] > nums[right],说明[left, mid - 1]必然有序
// 利用有序区间的端点值,判断是不是在序列当中,如果在,那么放弃掉无序的一边,如果不在,放弃掉有序的一边
// 此题的二段性,体现在,一段里面包含target,另外一段不包含target
int n = nums.size();
int left = 0, right = n - 1;
while (left < right) {
int mid = (left + right + 1) / 2;
// 如果右边有序
if (nums[mid] < nums[right]) {
// 如果右边符合要求,选择右边
if (nums[mid] <= target && target <= nums[right]) {
left = mid;
// 如果右边不符合要求,选择左边
} else {
right = mid - 1;
}
// 如果左边有序
} else {
// 如果左边符合条件
if (nums[left] <= target && target <= nums[mid - 1]) {
right = mid - 1;
// 如果左边不符合条件
} else {
left = mid;
}
}
}
if (nums[left] == target) {
return left;
} else {
return -1;
}
}
};
mid向上取整图示(mid在右区间)
class Solution {
public:
int search(vector<int>& nums, int target) {
// 如果 nums[mid] < nums[right],说明[mid, right]必然有序
// 如果 nums[mid] > nums[right],说明[left, mid - 1]必然有序
// 利用有序区间的端点值,判断是不是在序列当中,如果在,那么放弃掉无序的一边,如果不在,放弃掉有序的一边
// 此题的二段性,体现在,一段里面包含target,另外一段不包含target
int n = nums.size();
int left = 0, right = n - 1;
while (left < right) {
int mid = (left + right) / 2;
// 如果右边有序
if (nums[mid] < nums[right]) {
// 如果右边符合要求,选择右边
if (nums[mid + 1] <= target && target <= nums[right]) {
left = mid + 1;
// 如果右边不符合要求,选择左边
} else {
right = mid;
}
// 如果左边有序
} else {
// 如果左边符合条件
if (nums[left] <= target && target <= nums[mid]) {
right = mid;
// 如果左边不符合条件
} else {
left = mid + 1;
}
}
}
if (nums[left] == target) {
return left;
} else {
return -1;
}
}
};
mid向下取整图示(mid在左区间)