题目:
给定一个排序后的数组,包含n个整数,但这个数组已被旋转过很多次了,次数不详。请编写代码找出数组中的某个元素,假设数组元素原先是按升序排列的。若有多个相同元素,返回索引值最小的一个。
这道题是旋转次数不祥,但至少一次,前面发过一篇只旋转一次的旋转排序数组,可参考:
示例:
输入: arr = [15, 16, 19, 20, 25, 1, 3, 4, 5, 7, 10, 14], target = 5
输出: 8(元素5在该数组中的索引)
输入:arr = [5,5,5,1,2,3,4,5], target = 5
输出:0
解题思路:
本题我们采用二分法来解决。
1.确定左区间(left,mid)是升序的,如果目标值在左区间里,说明目标值就在左边序列,否则在右边
2.不确定左区间是升序的,(arr[left]<=target||target<=arr[mid]),这两个任意满足一个,都说明目标值在左区间里,不满足,则说明在右区间
3.遇到arr[left]==arr[mid]的情况,有可能是已经找到了目标值,还有可能是遇到重复值了,如果遇到了重复值,就要清除重复值。
code:
class Solution {
public:
int search(vector<int>& arr, int target) {
int n=arr.size();
if(n==1 && arr[0]!=target) return -1;
int left=0;
int right=n-1;
while(left<right)
{
int mid=left+(right-left)/2;
//左边区间是升序的
if(arr[left]<arr[mid])
{
//目标值处于arr[left]和arr[mid]之间,一定是在左边序列
if(target<=arr[mid]&&target>=arr[left])
{
right=mid;
}
//目标值在右边序列
else
{
left=mid+1;
}
}
//左边区间不是升序
else if(arr[left]>arr[mid])
{
//目标值在左边序列
if(arr[left]<=target||target<=arr[mid])
{
right=mid;
}
//目标值在右边序列
else
{
left=mid+1;
}
}
//遇到重复值,或者是已经找到了目标
else if(arr[left]==arr[mid])
{
//不等于target,说明还没找到
if(arr[left]!=target)
{
left++;//清除重复值
}
//找到了,直接将left赋值给right,将会结束循环
else
{
right=left;
}
}
}
//如果arr[left]等于目标值,说明找到了,直接返回下标
//否则,说明没找到,返回-1
return (arr[left]==target)?left:-1;
}
};