题目:
搜索旋转数组。给定一个排序后的数组,包含n个整数,但这个数组已被旋转过很多次了,次数不详。请编写代码找出数组中的某个元素,假设数组元素原先是按升序排列的。若有多个相同元素,返回索引值最小的一个。
示例1:
输入: arr = [15, 16, 19, 20, 25, 1, 3, 4, 5, 7, 10, 14], target = 5
输出: 8(元素5在该数组中的索引)
示例2:
输入:arr = [15, 16, 19, 20, 25, 1, 3, 4, 5, 7, 10, 14], target = 11
输出:-1 (没有找到)
提示:
arr 长度范围在[1, 1000000]之间
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/search-rotate-array-lcci
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
实际上需要判断断掉的点在哪里。去掉左右相等的值后,除了是纯升序数组这种情况,那么就是先升序,断点处,再升序这种情况,如示例。
本题由有序+查找,可以断定考察的是二分法。因此本题是基于二分法的变种,实际上是通过更复杂的条件判断来缩小查询的区间。
基于示例进行分析,如下图:
当取左时low = mid +1,取右时high = mid,这样做是因为题中要求如果有重复的元素时返回第一个元素的下标,这样的话我们一定是从右边往左边逐渐逼近,才能返回第一个元素的下标。
代码思路:
1.先将右边元素与第0个元素相比,去重,保证首位不一样,一样的话没有意义,如果查找的元素正是这个重复元素,也应该返回首元素地址的。
2.算mid的值,与第0个元素值进行比较。
3.如果mid的值大于第0个元素值,则如上述第一张图中情况,再进行条件判断,然后缩小区间;反之如第二张图。
4.最后low的位置即为查找的位置,如果low所在的值是目标值,则返回low,否则返回-1。
代码如下:
class Solution {
public int search(int[] arr, int target) {
if(arr.length == 0){
return -1;
}
int low = 0;
while(arr[low] == arr[high])
{
high--;
}
while(low < high){
int mid = low + (high - low )/2;
if(arr[mid] < arr[0]){
if(arr[0] <= target || target <= arr[mid]){
high = mid;
}else{
low = mid + 1;
}
}
else{
if(arr[0] <= target && target <= arr[mid]){
high = mid;
}else{
low = mid + 1;
}
}
}
return arr[low] == target ? low : -1;
}
}