搜索旋转排序数组

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

( 例如,数组 [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
题目分析:

首先看看二分查找,二分查找又称折半查找,是查找算法中比较常见的一种,它是一种在有序数组中查找某一特定元素的搜索算法。搜索过程从数组的中间元素开始,如果中间元素正好是要查找的元素,则搜索过程结束;如果某一特定元素大于或者小于中间元素,则在数组大于或小于中间元素的那一半中查找,而且跟开始一样从中间元素开始比较。如果在某一步骤数组为空,则代表找不到。这种搜索算法每一次比较都使搜索范围缩小一半。

示例代码:
public class S
{
    public static int search(int[] nums, int target)
    {
        int left = 0;
        int right = nums.length - 1;
        if (nums.length == 0)
            return -1;
        while (left <= right)
        {
            int mid = left + (right - left) / 2;
            if (nums[mid] == target)
                return mid;
            else if (nums[mid] < target)
                left = mid + 1;
            else
                right = mid - 1;
        }
        return -1;
    }

    public static void main(String[] args)
    {
        int res = search(new int[]{1,2,3,4,5,6}, 4);
        System.out.println(res);
    }
}
运行结果:

3

参照最基本的二分查找,看到数据结构是排序的数组,且目标是查找数据,则就会想到用二分查找,但是此题中的数组虽然是排序好的数组,但是它可能是按照某个点旋转过的,所以算法也需要有改进。

想到,既然数组是按照某点旋转过的,且数组升序排列,没有重复元素,那么旋转后的数组肯定分为两部分,数据大的与数据小的,这样就要分情况讨论:

以旋转数组[4,5,6,7,8,0,1,2,3]为例,前一段代表4,5,6,7,8,后一段代表0,1,2,3:
在这里插入图片描述

此时,根据target和nums[mid]的大小关系进行讨论

一、target > nums[mid],此时还需考虑nums[mid]和nums[0]的关系:

1.nums[mid] > nums[0],这种情况下

在这里插入图片描述
所以,要找到target,则left = mid + 1;

2.nums[mid] < nums[0],这种情况下又要分情况讨论target和nums[0]的关系:

(1).target < nums[0]

在这里插入图片描述
所以,要找到target,则left = mid + 1;

(2).target > nums[0]

在这里插入图片描述
所以,要找到target,则right = mid - 1;

二、target < nums[mid],此时也需考虑nums[mid]和nums[0]的关系::

1.nums[mid] < nums[0],这种情况下

在这里插入图片描述
所以,要找到target,则right = mid - 1;

2.nums[mid] > nums[0],这种情况下又要分情况讨论target和nums[0]的关系:

(1).target > nums[0]

在这里插入图片描述
所以,要找到target,则right = mid - 1;

(2).target < nums[0]

在这里插入图片描述
所以,要找到target,则left = mid + 1;

代码实现:
public int search(int[] nums, int target)
{
   if (nums.length == 0)
       return -1;
   int left = 0;
   int right = nums.length - 1;
   while (left <= right)
   {
       int mid = left + (right - left) / 2;
       if (nums[left] == target)
           return left;
       else if (nums[right] == target)
           return right;
       else if (nums[mid] == target)
           return mid;
       else
       {
           if (target > nums[mid])
           {
               if (nums[mid] > nums[0])
                   left = mid + 1;
               else
               {
                   if (target > nums[0])
                       right = mid - 1;
                   else
                       left = mid + 1;
               }
           }
           else
           {
               if (nums[mid] < nums[0])
                   right = mid - 1;
               else
               {
                   if (target < nums[0])
                       left = mid + 1;
                   else
                       right = mid - 1;
               }
           }
       }
   }
   return -1;
}
主函数:
public static void main(String[] args)
{
   S1 s = new S1();
   int res = s.search(new int[]{4, 5, 6, 7, 0, 1, 2}, 6);
   System.out.println(res);
}
运行结果:

2

  • 8
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值