程序员面试金典-面试题 10.03. 搜索旋转数组

题目:

搜索旋转数组。给定一个排序后的数组,包含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]之间

分析:

这道题做了很久,也看了一些人的答案,很多答案虽然看似二分,实际上还是在遍历数组。目前得到的最好的做法就是以左边区间是否有序为条件,来判断target值在哪个区间出现,进而减少搜索的空间。

不过当[5,5,5,5,5,2,3,4,5]或[5,2,3,4,5,5,5,5,5]如果搜索2的话。是最坏的情况,无法根据数组有序的条件判断出2在哪个区间,因为左右两个区间的边界也都为5。

具体思路写在程序的注释中了。

程序:

class Solution {
    public int search(int[] arr, int target) {
        return binarySearch(arr, target, 0, arr.length-1);
    }
    private int binarySearch(int[] arr, int target, int l, int r){
        if(l > r)
            return -1;
        if(l == r){
            if(target == arr[l])
                return l;
            else
                return -1;
        }
        int mid = l + (r - l) / 2;
        //如果左区间为升序的话
        if(arr[l] < arr[mid]){
            //target在左区间范围
            if(target <= arr[mid] && target >= arr[l])
                return binarySearch(arr, target, l, mid);
            else
                return binarySearch(arr, target, mid+1, r);
        }else if(arr[l] > arr[mid]){ //左区间不为升序
            //还是以左区间搜索为优先, 如果条件成立,target还是在左区间中
            if(target <= arr[mid] || target >= arr[l])
                return binarySearch(arr, target, l, mid);
            else
                return binarySearch(arr, target, mid+1, r);
        }else{
            //此时左区间两端点值相同,是最坏的情况两边都需要搜索
            //[5,5,5,5,5,2,3,4,5]或[5,2,3,4,5,5,5,5,5]如果搜索2的话
            //这两种情况左右区间都有可能存在,所以如果左区间找到了不为-1,就返回,否则返回右区间找的结果。
            //如果这种情况还有优化的余地希望告知一下
            int res = binarySearch(arr, target, l, mid);
            if(res != -1)
                return res;
            else
                return binarySearch(arr, target, mid+1, r);
        }
    }
}

 

posted @ 2020-03-13 16:30  silentteller  阅读(337)  评论(0编辑  收藏  举报