一、题目描述
来源:力扣(LeetCode)
整数数组 nums 按升序排列,数组中的值 互不相同 。
在传递给函数之前,nums 在预先未知的某个下标 k(0 <= 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 。
示例 1:
输入:nums = [4,5,6,7,0,1,2], target = 0
输出:4
示例 2:
输入:nums = [4,5,6,7,0,1,2], target = 3
输出:-1
示例 3:
输入:nums = [1], target = 0
输出:-1
提示:
- 1 <= nums.length <= 5000
- -10^4 <= nums[i] <= 10^4
- nums 中的每个值都 独一无二
- 题目数据保证 nums 在预先未知的某个下标上进行了旋转
- -10^4 <= target <= 10^4
二丶思路分析
二分法
因为数组是按升序排列
, 而数组在 k
点进行旋转后,旋转后的数组也会满足
- 前半段 >
num[0]
- 后半段 <
num[0]
我们可以通过这个条件 先找到旋转点k
,然后 - 判断
target
和旋转点
的值,判断target
落在了前半段还是后半段 - 然后再落点的半段中再次 二分查找 目标
target
三、代码实现
class Solution { public int search(int[] nums, int target) { int length = nums.length; if (length ==0) return -1; if (length ==1) return nums[0] == target ? 0 : -1; //找旋转点 int l =0, r = length -1; while (l < r) { int mid = l + r +1 >> 1; if (nums[mid] >= nums[0]) { l = mid; } else { r = mid -1; } } // 通过和 nums[0] 进行比较,判断 target 是在旋转点的左边还是右边 if (target >= nums[0]) { l =0; } else { l = l +1; r = length -1; } // 找 target while (l < r) { int mid = l + r +1 >> 1; if (nums[mid] <= target) { l = mid; } else { r = mid -1; } } return nums[r] == target ? r : -1; } }
复杂度分析
- 时间复杂度:
网络异常,图片无法展示|
- 空间复杂度:
网络异常,图片无法展示|
运行结果
网络异常,图片无法展示
|
总结
这道题目也是二分查找的允许,不过需要两次,第一次查找出旋转点,第二次查找出 target
.
通过二分法查找有序数列中某个数字的下标,只是二分法的一种应用,二分法的本质是找到性质的边界。
所以他不止可以用于查找有序数列中某个数字,还可以应用于更多的地方
继续加油~~