153.寻找旋转排序数组中的最小值
33. 搜索旋转排序数组
81. 搜索旋转排序数组 II
154. 寻找旋转排序数组中的最小值 II
33. 搜索旋转排序数组
解题思路:
这些题都是利用二分查找的思想,因为本来有序的数组,在经过旋转后,分成了两部分各自有序的排列,在旋转后的数组中寻找一个target,可以证明的是target一定会落在一个有序的区间内,那么只需要去确定这个区间就可以了。
nums[mid] > nums[left]) { //前半部分有序
中间的这个值大于left,根据数组是有序旋转得到的,说明落到了前半部分有序的地方,例如3,4,5,6,7,1,2
。
相反,说明是后半部分有序,例如,6,7,1,2,3,4,5
。
二分题目很多细节需要注意。
参考代码:
153.寻找旋转排序数组中的最小值
public int findMin(int[] nums) {
int left=0;
int right=nums.length-1;
while (left<right){
int mid=left+(right-left)/2;
if(nums[mid]>nums[right]){
left=mid+1;
}else {
right=mid;
}
}
return nums[left];
}
33. 搜索旋转排序数组
public int search(int[] nums, int target) {
int left = 0;
int right = nums.length - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] == target)
return mid;
if (nums[mid] >= nums[left]) {
if (target < nums[mid] && target >= nums[left]) {
right = mid - 1;
} else {
left = mid + 1;
}
} else {
if (target > nums[mid] && target <= nums[right]) {
left = mid + 1;
} else {
right = mid - 1;
}
}
}
return -1;
}
81. 搜索旋转排序数组 II
public boolean search(int[] nums, int target) {
if (nums.length < 1) {
return false;
}
int left = 0;
int right = nums.length - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] == target) {
return true;
}
if (nums[mid] == nums[left]) {
left++;
continue;
} else if (nums[mid] > nums[left]) { //前半部分有序
if (target >= nums[left] && target < nums[mid]) {
right = mid - 1;
} else {
left = mid + 1;
}
} else { //后半部分有序
if (target > nums[mid] && target <= nums[right]) {
left = mid + 1;
} else {
right = mid - 1;
}
}
}
return false;
}
154. 寻找旋转排序数组中的最小值 II
这道题有一些细节的问题:
1、为什么right=mid,left=mid+1?
因为普通的二分,我们一般会写成right=mid-1,left=mid+1,在选择到底是mid的那种情况的时候,只要是看结果可能在mid中出现来决定的,例如nums[mid]<nums[right],这个时候,mid可能是最小值,所以right=mid,这样如果mid就是最小值的话,结果就会被遍历得到,相反,nums[mid]>nums[right],这个时候,mid的位置都比right大了,所以结果肯定不会是mid,所以我们可以直接更新left指针为mid+1.
2、right=right-1会影响结果吗?答案是不会,因为如果说right指针左移的过程中,将最小的元素排除掉了,那么这个条件就是mid==right, 有两个最小的了,自相矛盾了,所以说不会出现这种情况。
public int findMin(int[] nums) {
int left=0;
int right=nums.length-1;
while (left<right){
int mid=left+(right-left)/2;
if(nums[mid]<nums[right]){
right=mid;
}else if(nums[mid]>nums[right]){
left=mid+1;
}else {
right=right-1;
}
}
return nums[left];
}