力扣题目
解题思路
java代码
力扣题目:
整数数组 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
解题思路:
-
如果数组长度为 1,直接检查数组中的值是否等于目标值,如果是,返回 0,否则返回 -1。
-
初始化两个指针
l
和r
,分别代表数组的左右边界。 -
进入一个循环,直到
l
大于r
:- 计算中间索引
mid
,即(l + r) / 2
。 - 如果中间值等于目标值,直接返回中间索引。
- 判断数组是否是升序排列:
- 如果数组的最小值(
nums[0]
)小于或等于中间值,说明左半部分是升序的。 - 如果目标值位于左半部分(即
nums[0]
到nums[mid]
),则将右边界r
移动到mid - 1
。 - 如果目标值位于右半部分(即
nums[mid]
到nums[n - 1]
),则将左边界l
移动到mid + 1
。
- 如果数组的最小值(
- 如果数组的最小值大于中间值,说明左半部分不是升序的。
- 如果目标值位于右半部分(即
nums[mid]
到nums[n - 1]
),则将左边界l
移动到mid + 1
。 - 如果目标值位于左半部分(即
nums[0]
到nums[mid]
),则将右边界r
移动到mid - 1
。
- 如果目标值位于右半部分(即
- 计算中间索引
-
如果循环结束后没有找到目标值,返回 -1。
java代码:
package org.example;
public class Leetcode33 {
public static void main(String[] args) {
int[] nums = {4,5,6,7,0,1,2};
System.out.println(search(nums, 0));
}
public static int search(int[] nums, int target) {
int n = nums.length;
// 旋转数组只有一个元素, 直接判断是不是目标值,如果是,返回下表,否则返回-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;
}
}
更多详细内容同步到公众号,感谢大家的支持!
并且没有任何收费项