二分查找进阶——搜索旋转排序数组——基于Java实现

在上一篇的文章中我们简单的介绍了什么是二分查找以及简单的实现,现在我们就来看看二分查找的进阶版——搜索旋转排序数组。

题目

整数数组 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,5,6,7] 在下标 3 处经旋转后可能变为 [4,5,6,7,0,1,2] 。

给你 旋转后 的数组 nums 和一个整数 target ,如果 nums 中存在这个目标值 target ,则返回它的下标,否则返回 -1 。

你必须设计一个时间复杂度为 O(log n) 的算法解决此问题。附上力扣链接

https://leetcode.cn/problems/search-in-rotated-sorted-array/?envType=problem-list-v2&envId=EBYPsbYA

解题思路 

对于这个问题可以利用二分查找的思想,但需要对传统的二分查找进行一些调整,因为数组是旋转排序的。 

对传统二分比较:

1、数组在某个未知点被分割成两部分,并交换了这两部分的顺序,但每部分内部仍然保持有序。 

2、但在每次迭代中,需要先判断当前中间元素将数组分为的两个部分中,哪一部分是有序的。然后,根据目标值与有序部分的关系,决定是继续在有序部分查找,还是排除有序部分,在另一部分继续查找。 

3、边界条件处理更为复杂,因为需要处理数组旋转带来的不确定性。 

特殊判断 

因此我们需要做出特殊一些额外的判断:

  • 如果 nums[left] <= nums[mid],说明左半部分是有序的。
    • 如果 target 在 nums[left] 和 nums[mid] 之间(包括 nums[mid]),则将搜索范围缩小到左半部分,即 right = mid - 1
    • 否则,target 必然在右半部分,更新 left = mid + 1
  • 如果 nums[mid] <= nums[right],说明右半部分是有序的。
    • 如果 target 在 nums[mid] 和 nums[right] 之间(包括 nums[right]),则将搜索范围缩小到右半部分,即 left = mid + 1
    • 否则,target 必然在左半部分,更新 right = mid - 1

 代码实现

public int search(int[] nums, int target) {
        int l=0,r=nums.length-1,m;
        if(r==0 && target!=nums[0]){
            return -1;
        }else if(r==0){
            return 0;
        }
        while(l<r){
            m=(l+r)>>>1;
            if(nums[m]==target){
                return m;
            }
            if(nums[l]<=nums[m]){
                if(nums[l]<=target && target<nums[m]){
                    r=m-1;
                }else{
                    l=m+1;
                }

            }else{
                if(nums[m]<target && target<=nums[r]){
                    l=m+1;
                }else{
                    r=m;
                }
            }
            if (nums[l] == target) {  
                return l;  
            } 
        }

        return -1;
    }

  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值