leetcode面试题 10.03(搜索旋转数组)--Java语言实现

匆匆过客 提交于 2020-08-15 05:38:15

求:

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

 

题目链接: https://leetcode-cn.com/problems/search-rotate-array-lcci/

 

解:

1、二分搜索子数组

因为要求返回的是与target相等的数组元素的最小索引,因此想到从左往后搜索,将旋转数组拆分为若干个有序的子数组,然后对每个子数组进行二分搜索,如果能够找到与target相等的元素,还需要考虑重复的问题,因此要向前遍历,直到找到索引最小的与target相同的元素。如果找不到与target相等的元素,返回-1。

时间复杂度:O(NlogN)

空间复杂度:O(1)

public int search(int[] arr, int target) {
    int start, end, ret;
    for (start = 0, end = 0; end < arr.length - 1; ++end) {
        if (arr[end + 1] < arr[end]) {
            ret = binarySearch(arr, target, start, end);
            if (ret != -1){
                while(ret>0 && arr[ret-1]==target) --ret;
                return ret;
            }
            else start = end+1;
        }
    }
    ret = binarySearch(arr, target, start, end);
    if (ret != -1){
        while(ret>0 && arr[ret-1]==target) --ret;
        return ret;
    }
    return -1;
}

private int binarySearch(int arr[], int target, int start, int end) {
    int low = start;
    int high = end;
    while (low <= high) {
        int mid = (low + high) / 2;
        if (arr[mid] == target) return mid;
        else if (arr[mid] < target) low = mid + 1;
        else high = mid - 1;
    }
    return -1;
}

 

2、二分搜索旋转数组

最优解,直接对旋转数组进行二分搜索,在二分搜索内部进行分支判断,修正左右端点。因为题目中的数组长度很大,当数组长度很大时,该方法明显优于方法1。

时间复杂度:O(logN),最坏情况每个元素都需要遍历,为O(N)

空间复杂度:O(1)

public int search(int[] arr, int target) {
    int len = arr.length;
    int left = 0, right = len - 1;
    while (left < right) {
        int mid = left + (right - left) / 2;
        if (arr[mid] < arr[right]) {
            if (arr[mid] < target && (target < arr[right] || (target == arr[right] && arr[left] != target))) {
                left = mid + 1;
            } else {
                right = mid;
            }
        } else if (arr[mid] > arr[right]) {
            if (arr[mid] < target || target < arr[right] || (target == arr[right] && arr[left] != target)) {
                left = mid + 1;
            } else {
                right = mid;
            }
        } else {
            right--;
        }
    }
    return arr[left] == target ? left : -1;
}

 

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!