描述

给定一个整数数组nums,按升序排序,数组中的元素各不相同。
nums数组在传递给search函数之前,会在预先未知的某个下标 t(0 <= t <= nums.length-1)上进行旋转,让数组变为[nums[t], nums[t+1], ..., nums[nums.length-1], nums[0], nums[1], ..., nums[t-1]]。
比如,数组[0,2,4,6,8,10]在下标3处旋转之后变为[6,8,10,0,2,4]
现在给定一个旋转后的数组nums和一个整数target,请你查找这个数组是不是存在这个target,如果存在,那么返回它的下标,如果不存在,返回-1

示例1

输入:
[6,8,10,0,2,4],10

返回值:
2

示例2

输入:
[6,8,10,0,2,4],3

返回值:
-1

示例3

输入:
[2],1

返回值:
-1

思路

在有序数组中找某个数字,最常用的方法就是 二分查找,这道题唯一的不同就是会旋转字符串的某部分,会导致字符串部分有序,不过这并不影响 二分查找 的使用。
当找到 mid 位置时,判断 0 - mid 是否时有序的,如果是有序的,则去判断 target 是否在 0 - mid 中,如果在的话,更新 end = mid - 1就行;如果不在 则更新 start = mid + 1,和 二分查找原理很相似,只这次不过先判断是否有序,在判断目标值是否在区间内。

AC 代码

 public int search (int[] nums, int target) {
        // write code here
        if (nums == null || nums.length < 1) {
            return -1;
        }
        if (nums.length == 1) {
            return nums[0] == target ? 0 : -1;
        }

        int start = 0, end = nums.length - 1;
        while (end >= start) {
            // 找到 左右指针中间位置
            int mid = (end + start) >> 1;
            if (nums[mid] == target) {
                return mid;
            }
            // 在左侧升序数组中
            if (nums[0] <= nums[mid]) {
                // 在开头和 mid 之间,那么 右指针则为 mid -1
                if (target >= nums[0] && target < nums[mid]) {
                    end = mid -1;
                } else {
                    start = mid + 1;
                }
            } else {
                // 如果在 mid 和end 之前,更新 start 为 mid = 1
                if (target > nums[mid] && target <= nums[end]) {
                    start = mid + 1;
                } else {
                    end = mid - 1;
                }
            }


        }
        return -1;
    }
  • 时间复杂度: O(logn),其中 n 为 nums 数组的大小。整个算法时间复杂度即为二分查找的时间复杂度 O(logn)。

  • 空间复杂度: O(1) 。

最后

这道题虽然是部分有序的,但是依然使用 二分查找 为核心思想。
大家可以去 【牛客网-题库-在线编程】去练习一下。
可以去微信搜索:【蘑菇睡不着】交个朋友~
也可以扫描下方二维码。

图片说明