携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第25天,点击查看活动详情
题目描述
整数数组 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 。
你必须设计一个时间复杂度为 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 示例 3:
输入:nums = [1], target = 0 输出:-1
提示:
- 1 <= nums.length <= 5000
- -104 <= nums[i] <= 104
- nums 中的每个值都 独一无二
- 题目数据保证 nums 在预先未知的某个下标上进行了旋转
- -104 <= target <= 104
题目元素
- 给定一个无重复元素的数组,数组中某一个节点前后都成升序排列,且节点之前的元素都大于节点之后的元素;
- 给定target,求target在数组中的位置,如果不存在则返回-1;
- 要求时间复杂度为O(log n),看见logn的复杂度就要联想到二分法,这道题可以用二分法解决。
解题思路
逆转后的数组,在节点k前后一定是呈升序的两个数组,且第一个数组的值都要大于第二个数组。 所以可以将数组进行二分,数组最左边的值叫left,数组最右边的值叫right,找到数组中点mid,然后将任意一边的值和mid的值作比较,假定我们取left和mid作比较,则有两种情况:
- mid >= left,此时数组nums中[left,mid]的值一定是升序的,即它一定是有序的数组。这里又有两种情况:一种是正好target在这个有序范围内,则可以继续对这个有序数组进行二分,知道找到target的位置或者二分后的数组大小为1,但是仍未找到target,则返回-1;另一种是target不在这个区间内,则需要在[mid,right]数组中寻找有序数组,且target在这个有序数组范围内。
- mid < left,次数数组nums中的[mid,right]的所有元素一定是升序的,处理方式和上一种情况如出一辙,不一样的是,这里需要查找的范围是[mid,right]。
例如给定数组nums[5,6,7,8,9,1,2,3,4],target为2。
第一次mid=4,nums[4] = 9,此时9>5,所以数组[0,4]一定是有序的,然后判断target在不在此范围内,不在。此时数组范围缩小到[1,2,3,4](二分);
第二次mid=2,mid==target,所以直接返回2的位置。
记住一定要先判断数组是有序的,然后才能将target和这个数组的首尾元素进行比较。
代码实现
public static int search(int[] nums, int target) {
// 获取数组中点
int left = 0;
int right = nums.length-1;
while (left <= right) {
int mid = left+(right-left)/2;
if (target == nums[right]) {
return right;
} else if (target == nums[left]) {
return left;
} else if (target == nums[mid]) {
return mid;
}
if (nums[mid] >= nums[left] ) {
if (nums[left] < target && target < nums[mid]) {
// 呈线性关系,且目标target在左边
right = --mid;
} else {
// 查找右边数组
left = ++mid;
}
}else {
if (nums[mid] <= nums[right] && nums[mid] < target && target < nums[right]) {
// 右边呈线性关系,且目标在右边
left = ++mid;
} else {
//查找左边数组
right = --mid;
}
//
}
}
return -1;
}