码迷,mamicode.com
首页 > 编程语言 > 详细

leetcode题解之33. 搜索旋转排序数组

时间:2020-06-26 16:51:41      阅读:56      评论:0      收藏:0      [点我收藏+]

标签:假设   load   信息   pos   应该   operation   word   button   str   

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

( 例如,数组 [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

?? 视频题解

code:

vid:

uuid:

requestId:

播放时间:

提示信息

技术图片
字幕
    倍速
      清晰度
        音轨
          倍速正常
          字幕Off
          音轨
          清晰度

          ?? 文字题解

          方法一:二分搜索

          思路和算法

          题目要求算法时间复杂度必须是 O(log?n)O(\log n) 的级别,这提示我们可以使用二分搜索的方法。

          但是数组本身不是有序的,进行旋转后只保证了数组的局部是有序的,这还能进行二分搜索吗?答案是可以的。

          可以发现的是,我们将数组从中间分开成左右两部分的时候,一定有一部分的数组是有序的。拿示例来看,我们从 6 这个位置分开以后数组变成了 [4, 5, 6][7, 0, 1, 2] 两个部分,其中左边 [4, 5, 6] 这个部分的数组是有序的,其他也是如此。

          这启示我们可以在常规二分搜索的时候查看当前 mid 为分割位置分割出来的两个部分 [l, mid][mid + 1, r] 哪个部分是有序的,并根据有序的那个部分确定我们该如何改变二分搜索的上下界,因为我们能够根据有序的那部分判断出 target 在不在这个部分:

          • 如果 [l, mid - 1] 是有序数组,且 target 的大小满足 [nums[l],nums[mid])[\textit{nums}[l],\textit{nums}[mid]),则我们应该将搜索范围缩小至 [l, mid - 1],否则在 [mid + 1, r] 中寻找。
          • 如果 [mid, r] 是有序数组,且 target 的大小满足 (nums[mid+1],nums[r]](\textit{nums}[mid+1],\textit{nums}[r]],则我们应该将搜索范围缩小至 [mid + 1, r],否则在 [l, mid - 1] 中寻找。

          技术图片

          需要注意的是,二分的写法有很多种,所以在判断 target 大小与有序部分的关系的时候可能会出现细节上的差别。

          class Solution {
          public:
              int search(vector<int>& nums, int target) {
                  int n = (int)nums.size();
                  if (!n) return -1;
                  if (n == 1) return nums[0] == target ? 0 : -1;
                  int l = 0, r = n - 1;
                  while (l <= r) {
                      int mid = (l + r) / 2;
                      if (nums[mid] == target) return mid;
                      if (nums[0] <= nums[mid]) {
                          if (nums[0] <= target && target < nums[mid]) {
                              r = mid - 1;
                          } else {
                              l = mid + 1;
                          }
                      } else {
                          if (nums[mid] < target && target <= nums[n - 1]) {
                              l = mid + 1;
                          } else {
                              r = mid - 1;
                          }
                      }
                  }
                  return -1;
              }
          };
          
          class Solution:
              def search(self, nums: List[int], target: int) -> int:
                  if not nums:
                      return -1
                  l, r = 0, len(nums) - 1
                  while l <= r:
                      mid = (l + r) // 2
                      if nums[mid] == target:
                          return mid
                      if nums[0] <= nums[mid]:
                          if nums[0] <= target < nums[mid]:
                              r = mid - 1
                          else:
                              l = mid + 1
                      else:
                          if nums[mid] < target <= nums[len(nums) - 1]:
                              l = mid + 1
                          else:
                              r = mid - 1
                  return -1
          

          复杂度分析

          • 时间复杂度: O(log?n)O(\log n),其中 nnnums[]\textit{nums}[] 数组的大小。整个算法时间复杂度即为二分搜索的时间复杂度 O(log?n)O(\log n)

          • 空间复杂度: O(1)O(1) 。我们只需要常数级别的空间存放变量。

          更多: [https://www.jianshu.com/p/82d60c8ae4e8](https://www.jianshu.com/p/82d60c8ae4e8)

          leetcode题解之33. 搜索旋转排序数组

          标签:假设   load   信息   pos   应该   operation   word   button   str   

          原文地址:https://www.cnblogs.com/leetcodetijie/p/13195118.html

          (0)
          (0)
             
          举报
          评论 一句话评论(0
          登录后才能评论!
          分享档案
          周排行
          mamicode.com排行更多图片
          © 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
          迷上了代码!