介绍
- 旋转数组的定义:
排好序的数组 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] 。 - 相关问题
- 153. 寻找旋转排序数组中的最小值
寻找旋转数组中的最小值,数组中每个元素的唯一的。 - 154. 寻找旋转排序数组中的最小值 II
寻找旋转数组中的最小值,数组中包含重复元素。 - 33. 搜索旋转排序数组
在寻找数组中查询是否存在某个值,不包含重复元素。 - 81. 搜索旋转排序数组 II
在寻找数组中查询是否存在某个值,包含重复元素。
以上题目均来自 LeetCode
二分查找模板
- 模板一
public binarySearch(int[] nums, int target) {
int n = nums.length;
if (n == 0) return -1;
int left = 0, right = n - 1, mid;
while (left <= right) {
mid = left + (right - left) / 2;
if (nums[mid] == target) {
return mid;
} else if (nums[mid] < target) {
left = mid + 1;
} else {
right = mid - 1;
}
}
}
- 模板二
public binarySearch(int[] nums, int target) {
int n = nums.length;
int left = 0, right = n, mid;
while (left < right) {
mid = left + (right - left) / 2;
if (nums[mid] < target) {
left = mid + 1;
} else {
right = mid;
}
}
}
- 变形
public binarySearch(int[] nums, int target) {
int n = nums.length;
int left = 0, right = n, mid;
while (left < right) {
mid = left + (right - left + 1) / 2;
if (nums[mid] > target) {
right = mid - 1;
} else {
left = mid;
}
}
}
解法
对于排序数组的查找,很容易想到二分法。
对于旋转数组,依然可以使用二分法进行查找。
问题1
不包含重复值的最小值的查询
使用模板二
class Solution {
public int findMin(int[] nums) {
int n = nums.length;
int i = 0, j = n, mid;
while (i < j) {
mid = i + (j - i) / 2;
if (nums[mid] > nums[n - 1]) {
i = mid + 1;
} else {
j = mid;
}
}
return nums[i];
}
}
问题2
包含重复值的最小值的查询
在模板二基础上,针对题目变化
class Solution {
public int findMin(int[] nums) {
int n = nums.length;
int left = 0, right = n - 1, mid;
while (left < right) {
mid = left + (right - left) / 2;
if (nums[mid] > nums[right]) {
left = mid + 1;
} else if (nums[mid] < nums[right]) {
right = mid;
} else {
right--;
}
}
return nums[left];
}
}
问题3
不包含重复值的某个元素的查找
使用模板一
class Solution {
public int search(int[] nums, int target) {
int n = nums.length;
int left = 0, right = n - 1, mid;
while (left <= right) {
mid = left + (right - left) / 2;
if (nums[mid] == target) {
return mid;
} else if (nums[mid] > target) {
if (nums[mid] > nums[n - 1] && target <= nums[n - 1]) {
left = mid + 1;
} else {
right = mid - 1;
}
} else {
if (nums[mid] <= nums[n - 1] && target > nums[n - 1]) {
right = mid - 1;
} else {
left = mid + 1;
}
}
}
return -1;
}
}
问题4
包含重复元素的值查找
使用模板一
class Solution {
public boolean search(int[] nums, int target) {
int n = nums.length;
int left = 0, right = n - 1, mid;
while (left <= right) {
mid = left + (right - left) / 2;
if (nums[mid] == target) {
return true;
}
// 因为下面用到了n-1,所以不能用right;如果此处用right,下面判断就要用nums[0]
if (nums[left] == nums[mid]) {
left++;
continue;
}
if (nums[mid] > target) {
if (nums[mid] > nums[n - 1] && target <= nums[n - 1]) {
left = mid + 1;
} else {
right = mid - 1;
}
} else {
if (nums[mid] <= nums[n - 1] && target > nums[n - 1]) {
right = mid - 1;
} else {
left = mid + 1;
}
}
}
return false;
}
}
虽然使用了二分查找,但是由于存在重复元素,当数组中所有元素相等且不等于target时,需要遍历数组中所有元素。因此时间复杂度为O(n)。