搜索旋转排序数组

题目

假设按照升序排序的数组在预先未知的某个点上进行了旋转。( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。

搜索一个给定的目标值,如果数组中存在这个目标值,则返回它的索引,否则返回 -1 。

假设数组中不存在重复的元素。算法时间复杂度必须是 O(log n) 级别。

  示例 1:

      输入: nums = [4,5,6,7,0,1,2],  target = 0      输出: 4

思路

可以将数组从中间分开成左右两部分的时候,一定有一部分数组是有序的。拿示例来看,我们从 6 这个位置分开以后数组变成了 [4, 5, 6] 和 [7, 0, 1, 2] 两个部分,其中左边 [4, 5, 6] 这个部分的数组是有序的,其他也是如此。

所以可以在常规二分搜索的时候查看当前 mid 为分割位置分割出来的两个部分 [l, mid] 和 [mid + 1, r] 哪个部分是有序的,并根据有序的那个部分确定我们该如何改变二分搜索的上下界,因为我们能够根据有序的那部分, 判断出 target 在不在这个部分:

       如果 [l,  mid - 1] 是有序数组,且 target 的大小满足 [nums[l], nums[mid]),则我们应该将搜索范围缩小至 [l,  mid - 1],否则在 [mid + 1,  r] 中寻找。

       如果 [mid,  r] 是有序数组,且 target 的大小满足 (nums[mid+1], nums[r]],则我们应该将搜索范围缩小至 [mid + 1,  r],否则在 [l,  mid - 1] 中寻找。

程序实现:

public int search(int[] nums, int target) {
        int left = 0;
        int right = nums.length - 1;

        while (left <= right) {
            int mid = (left + right) / 2;

            if (nums[mid] == target) {
                return mid;
            } else if (nums[left] == target) {
                return left;
            } else if (nums[right] == target) {
                return right;
            }else if (nums[mid] > nums[0]) { //左边有序
          if (target < nums[mid]) {
            if (target > nums[0]) {
              right = mid - 1;
            } else {
              left = mid + 1;
            }
          } else {
            left = mid + 1;
          }
      } else if (nums[mid] < nums[0]) { //右边有序
          if (target > nums[mid]) {
            if (target < nums[right]) {
              left = mid + 1;
            } else {
              right = mid - 1;
            }
          } else {
            right = mid - 1;
          }
      }

     return -1; }

 

posted @ 2020-11-11 09:51  linghu_java  阅读(231)  评论(0编辑  收藏  举报