LeetCode 精选 TOP 面试题(Java 实现)—— 搜索旋转排序数组

一、题目描述

1.1 题目
  • 搜索旋转排序数组

  • 搜索一个给定的目标值,如果数组中存在这个目标值,则返回它的索引,否则返回 -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
1.2 知识点
  • 二分查找
1.3 题目链接

二、解题思路

2.1 自研思路

  这道题是二分查找算法的一个变种题型,但是相对来说因为可以假设不存在重复元素,因此难度会低一些。这道题的解题思想就是将原数组进行分割,因为原数组是一个有序数组在某一随机点翻转后得到的,所以通过观察可以发现每次从原数组的中点进行分割,一定可以得到一个有序数组和一个翻转数组,对于有序数组我们只需要判断它的端点值,就可以一次性的筛选掉一半的元素(二分查找的思想也是这样,每次通过中点的比较一次性淘汰一半的元素)。

  因此,分析后我们可以发现这道题的重点其实是如何确定中点分割后两侧数组的有序性,在这里我们可以以一侧的数组为参照(左右都可以),我这里是使用分割后左侧的数组作为参照,易得当左侧数组的最左端点值小于中点值时,可以证明这时左侧的数组是一定有序的,反之当左侧数组的最左端点值大于中点值时,可以证明这时右侧的数组一定是有序的。

  因此接下来就比较容易分析了,当我要查找一个数字的时候,先拿它与中点值进行比较,假如当其值大于中点值时,再进行判断此时最左端点值是否大于或等于中点值(右侧数组是否有序),如果最左端点值大于或等于中点值证明此时右侧数组一定是有序的(且必为升序),且因为右侧数组为有序且升序数组,那么该数组的最右端点一定是该数组的最大值,那么我们再用这个最大值与我们的目标值进行比较,如果我们的目标值大于这个最大值则证明我们要搜索的目标值是 一定 不存在于右侧这个数组中的,此时我们可以直接舍弃右侧数组(right = mid - 1),反之在其它的情况下目标值则 可能 存在于右侧数组中(但是这里因为左侧数组是翻转数组,所以我们是不能确定的),因此此时舍弃右侧数组(left = mid + 1)。

2.2 示例思路

  这里的解题思路是一样的,但是其求中点坐标的方式还是值得借鉴的,即使用 mid = left + (right - left) / 2来求中点坐标。

三、实现代码

3.1 自研实现
class Solution {
    public int search(int[] nums, int target) {

        if(nums.length <= 0) return -1;
        int left = 0, right = nums.length-1, mid = 0;

        while(left <= right){
            mid = (left+right)/2;
            if(nums[mid] == target)
                return mid;

            if(target > nums[mid]){
                if(nums[left] >= nums[mid] && target > nums[right])
                    right = mid-1;
                else
                    left = mid+1;
            } else {
                if(nums[left] <= nums[mid] && target < nums[left])
                    left = mid+1;
                else
                    right = mid-1;
            }
        }
        return -1;
    }
}
3.2 示例代码
class Solution {
    public int search(int[] nums, int target) {
        int left = 0;
        int right = nums.length - 1;
        while(left<=right){
            int mid = left + (right - left) / 2;
            if(nums[mid]==target){
                return mid;
            }else if(nums[mid]<nums[right]){
                if(nums[mid]<target&&target<=nums[right]){
                    left = mid + 1;
                }else{
                    right = mid - 1;
                }
            }else{
                if(nums[mid]>target&&target>=nums[left]){
                    right = mid - 1;
                }else{
                    left = mid + 1;
                }
            }
        }
        return -1;
    }
}
发布了244 篇原创文章 · 获赞 32 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/qq_40697071/article/details/103925138