力扣第八十一题-搜索旋转排序数组 II

169 阅读1分钟

「这是我参与11月更文挑战的第9天,活动详情查看:2021最后一次更文挑战

前言

力扣第八十一题 搜索旋转排序数组 II 如下所示:

已知存在一个按非降序排列的整数数组 nums ,数组中的值不必互不相同。

在传递给函数之前,nums 在预先未知的某个下标 k0 <= k < nums.length)上进行了 旋转 ,使数组变为 [nums[k], nums[k+1], ..., nums[n-1], nums[0], nums[1], ..., nums[k-1]](下标 从 0 开始 计数)。例如, [0,1,2,4,4,4,5,6,6,7] 在下标 5 处经旋转后可能变为 [4,5,6,6,7,0,1,2,4,4] 。

给你 旋转后 的数组 nums 和一个整数 target ,请你编写一个函数来判断给定的目标值是否存在于数组中。如果 nums 中存在这个目标值 target ,则返回 true ,否则返回 false 。

示例 1:

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

示例 2:

输入: nums = [2,5,6,0,0,1,2], target = 3
输出: false

一、思路

这一题与前面的三十三题,唯一的不同就是数组中可能会有重复值,所以基本的解题思路是差不多的,仍然使用的是二分法

这一题的关键就是通过 targetnums[mid]nums[left]nums[right] 进行比较,从而判断 target 是否在 [0 ~ k] 的非递减区间内,或 target 是否在 [k ~ n] 的非递减区间内。

出现相同的值带来的影响就是,当 nums[mid] == nums[left] == nums[right] 时,无法判断 target 是在 [left, mid][mid, right] 中。所以,当出现 这种情况时,我们简单的将 leftright 都减一。

大致的实现步骤如下所示:

  1. 初始化值, left = 0right = len -1
  2. 使用 二分法 进行取值,nums[mid] 大致会出现以下几种情况
  • nums[left] <= nums[mid] 说明左半边是非递减的,如果值在左半边,则丢弃右边。反之也是一样
  • nums[left] <= nums[mid] 说明右半边包含了 [k ~ n] 这一段,判断值是否在 [k ~ n] 这一段非递减区间上,如果在则丢弃左半边。如果不在,则丢弃右半边。

举个例子

此处以 nums = {3,1,2,2,2}, target =1 作为例子

  1. left = 0, right = 4, mid = 2,因 nums[left] > nums[mid],且值不在 [k ~ n] 中,故将 right = mid -1 = 1
  2. left = 0, right = 1, mid = 0,此时 nums[right] == target,故返回 true

二、实现

实现代码

    public boolean search(int[] nums, int target) {
        int len = nums.length;
        if (len == 0) {
            return false;
        }
        int left = 0, right = len - 1;
        while (left <= right) {
            int mid = (left + right) / 2;
            // 相等的情况
            if (nums[mid] == target || nums[left] == target || nums[right] == target) {
                return true;
            }
            // 特殊情况:缩小区间
            if (nums[left] == nums[mid] && nums[mid] == nums[right]) {
                ++left;
                --right;
            } else if (nums[left] <= nums[mid]) {   // 左边是递增的
                if (nums[left] < target && target < nums[mid]) {   // 值在左边
                    right = mid - 1;
                } else {
                    left = mid + 1;
                }
            } else {    // 该区间有[0 ~ k]
                if (nums[mid] < target && target < nums[len - 1]) {    // 判断是否在[0 ~ k] 上
                    left = mid + 1;
                } else {
                    right = mid - 1;
                }
            }
        }
        return false;
    }

测试代码

    public static void main(String[] args) {
        int[] nums = {3,1,2,2,2};
        int target = 1;
        boolean flag = new Number81().search(nums, target);
        System.out.println("test");
    }

结果

image.png

三、总结

感谢看到最后,非常荣幸能够帮助到你~♥

如果你觉得我写的还不错的话,不妨给我点个赞吧!如有疑问,也可评论区见~