LeetCode0033-搜索旋转排序数组

LeetCode 0032-搜索旋转排序数组

题目:

假设按照升序排序的数组在预先未知的某个点上进行了旋转。

( 例如,数组 [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
示例 2:
输入: nums = [4,5,6,7,0,1,2], target = 3
输出: -1

分析:

题目要求时间复杂度为O(log n)的级别,这提示使用二分搜索的方法。

但是数组本身不是有序的,进行旋转后只保证了数组的局部有序的,如何进行二分查找?
可以发现,将数组从中间分开成左右俩个部分的时候,一定有一个部分的数组是有序的,从示例中的中间位置分开数组后变成了 [4, 5, 6] 和[7, 0, 1, 2]俩个部分,其中左边的部分[4, 5, 6]这个部分是有序的,递归下去也是如此。

从这可以发现,可以在常规的二分搜索的时候查看当前 mid 为分割出来的俩个部分[left, mid] 和[mid + 1, right]中哪一个是有序的,并根据有序的那部分确定如何改变二分搜索的上下界,因为能够根据有序的那部分判断出 target 在不在这个部分:

  • 如果[left, mid - 1] 是有序数组,且 target 的大小满足 nums[left] <= target <nums[mid],则应该将搜素范围缩小至[left, mid-1],否则在 [mid+1, right]中查找。

  • 如果[mid,right] 是有序数组,且target 的大小满足 nums[mid + 1]< target <= nums[right],则应该将搜索范围缩小至[mid + 1, right],否则在[left, mid - 1]中寻找。

代码:

/**
 * 0033-搜索旋转排序数组
 * 假设按照升序排序的数组在预先未知的某个点上进行了旋转。
 * <p>
 * ( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。
 * <p>
 * 搜索一个给定的目标值,如果数组中存在这个目标值,则返回它的索引,否则返回 -1 。
 * <p>
 * 你可以假设数组中不存在重复的元素。
 * <p>
 * 你的算法时间复杂度必须是 O(log n) 级别。
 * <p>
 * 示例 1:
 * <p>
 * 输入: nums = [4,5,6,7,0,1,2], target = 0
 * 输出: 4
 * <p>
 * 示例 2:
 * <p>
 * 输入: nums = [4,5,6,7,0,1,2], target = 3
 * 输出: -1
 */

/**
 * 二分查找
 */
class Solution {
    public int search(int[] nums, int target) {
        // 获取数组的总长度
        int length = nums.length;
        // 如果数组为空,或者长度为0,直接返回
        if (nums == null || length == 0) {
            return -1;
        }
        // 如果数组长度为1,直接比较返回即可
        if (length == 1) {
            return nums[0] == target ? 0 : -1;
        }
        // 设置左右边界
        int left = 0, right = length - 1;
        /**
         * 二分查找
         */
        while (left <= right) {
            // 取中间位置值
            int mid = (left + right) / 2;
            // 如果中间位置的值符合查找条件,直接返回
            if (nums[mid] == target) {
                return mid;
            }
            // 左半部分有序
            if (nums[left] <= nums[mid]) {
                // target 可能在左半部分,移动右边指针,舍去右半部分
                if (nums[left] <= target && target < nums[mid]) {
                    right = mid - 1;
                } else {// target 不可能在左半部分,移动左边指针,舍去左半部分
                    left = mid + 1;
                }
            } else { // 右半部分有序
                // target 可能在右半部分,移动左指针,舍去左半部分
                if (nums[mid] < target && target <= nums[right]) {
                    left = mid + 1;
                } else {  // target 不可能在右半部分,移动右指针,舍去右半部分
                    right = mid - 1;
                }
            }
        }
        // 没找到,返回
        return -1;
    }
}

/**
 * 测试类
 */
public class Study0033 {
    public static void main(String[] args) {
        System.out.println(new Solution().search(new int[]{4, 5, 6, 7, 0, 1, 2}, 0));
    }
}

结果:

在这里插入图片描述

©️2020 CSDN 皮肤主题: 游动-白 设计师:上身试试 返回首页