感觉写的很low很low,还干了90%的人,查找有序数组,虽然是有序的有点奇怪,但是还是一下想到二分
我的思路是先通过二分查找找到分割点,也就是最小值。那么分割点左边以及分割点右边都是有序的,根据target的值来判断去哪边寻找,再去哪边二分就行了。难的就是找最小值,剑指offer有一题一样的,我们在找最小值的过程中也加以判断,如果找到target的话直接返回就好了。如果mid>right,证明最小值一定在右边,left=mid+1,mid直接舍弃,因为太大了。如果mid小于right,证明在mid到right是单调递增的,所以在左边找,mid不能舍弃。如果相等,那就不一定了,左右都有可能,但是right一定不可能了,它一定>=最小值,反正mid还在,直接舍弃right,将right–缩小范围即可。最后结束循环时的left就是切分点。然后去两个区间二分即可。
class Solution {
public:
int search(vector<int>& nums, int target) {
if(nums.size() == 0) return -1;
//被旋转过的,在分界线两侧还是有序的,用二分查找即可,logn,先通过二分查找找出切分点,切分点就是最小的那个数字
//再在两个有序数组里找即可
int left = 0, right = nums.size()-1;
int qiefen;//切分点是
while(left <= right){
int mid = left + (right-left)/2;
if(nums[mid] == target) return mid;
if(nums[mid] > nums[right]){
left = mid+1;//mid没用了,因为mid不是最小的
}
else if(nums[mid] < nums[right]){
right = mid;
}
else{
right--;
}
}
int left1 = 0, right1 = left-1,left2 = left, right2 = nums.size()-1;
//两个有序数组
/*if((target < nums[left1] && target > nums[right1])||
target < nums[left2] || target > nums[right1]){
return -1;
}*/
if(target > nums[right2]){//在左边查
while(left1 <= right1){
int mid = left1 + (right1-left1)/2;
if(nums[mid]==target) return mid;
else if(nums[mid] > target) right1 = mid-1;
else left1 = mid+1;
}
}
else{
while(left2 <= right2){
int mid = left2 + (right2-left2)/2;
if(nums[mid] == target) return mid;
else if(nums[mid] > target) right2 = mid-1;
else left2 =mid+1;
}
}
return -1;
}
};
不是找某个特定数,就是返回left,找某个特定数一定能在里面找到,找不到就返回-1。先找到最小值。找某个特定数要left严格大于right才行,找区间left=right就可以退出了。
class Solution {
public:
int search(vector<int>& nums, int target) {
//有序数组的查找=二分查找
//两边二分解决,第一遍找出最小值,也就是分割界限,然后去左右分别二分
int left = 0, right = nums.size()-1;
//循环什么时候结束?最后返回的是left的值,在搜边界的时候如果搜到target也行
//不是找某个数,而是为了确定边界之类的,返回的left,而且是等于就可以退出了
while(left < right){
int mid = left + (right-left)/2;
if(nums[mid] == target) return mid;
//根据mid和high来查找边界,right如果大于mid,证明mid到right是有序的,在左边
//如果right小于mid,证明无序,在右边
//如果等于就让right--缩小范围
if(nums[right] > nums[mid]){
//mid比较小,不能直接忽视
right = mid;
}
else if(nums[right] < nums[mid]){
left = mid+1;
}
else{
right--;
}
}
//此时left就是最小值,它到最后是有序的,它前面的也是有序的
int left1 = 0, right1 = left-1, left2 = left, right2 = nums.size()-1;
//也可以提前判断是否存在,如果大于最大或者小于最小就是不存在
//然后判断target在哪边
if(target > nums[right2]){
//找某个数的时候必须要严格大于才退出,等于不能退出!!
while(left1 <= right1){
int mid = left1 + (right1-left1)/2;
if(nums[mid] == target){
return mid;
}
else if(nums[mid] < target){
//如果小于就去右边,mid不要了,因为mid不可能是target了
left1 = mid+1;
}
else{
right1 = mid-1;
}
}
}
else{
while(left2 <= right2){
int mid = left2 + (right2 - left2)/2;
if(nums[mid] == target){
return mid;
}
else if(nums[mid] < target){
left2 = mid+1;
}
else{
right2 = mid-1;
}
}
}
return -1;
}
};