题目:力扣https://leetcode-cn.com/problems/search-in-rotated-sorted-array/
class Solution {
public int search(int[] nums, int target) {
int left = 0;
int right = nums.length-1;
while(left<=right){
int mid = (left+right)/2;
if(target == nums[mid]){
return mid;
}else if(nums[mid]<nums[right]){
if(nums[mid]<target && target<=nums[right]){
left = mid+1;
}else{
right = mid-1;
}
}else{
if(nums[left]<=target && target<nums[mid]){
right = mid-1;
}else{
left = mid+1;
}
}
}
return -1;
}
}
思路:这道题一开始挺难理解题意,大概意思是将一段升序排列的数字在某个地方分开两截,然后调换它们的位置,需要通过算法在调换后的数字中找到targert,找到则返回下标,找不到则返回-1。一开始是想用递归的方法解题,但是在传入参数中的数组有点难处理,因为最后是要返回原数组中的下标,所以最后用了循环替代递归。
大概思路是,二分查找,取中间位置的数字,判断它是不是我们要找的target,若是返回下标,否则,判断这个中间数字左右两段数字哪一段是完全有序的。(因为原本的数字是升序排列的,只是在某处分开了然后换位置了,所以中间位置的左右两段数至少有一段是完全有序的,判断有序的方法是“左小右大”。)接着判断target是否在有序数的区间内,若是则对该区间继续二分查找;若target不再有序数的区间内,则毫无疑问一定在另一个不完全有序的区间内,对不完全有序的区间故技重施即可。若循环结束了,仍找不到target证明,这段数中没有,返回-1即可。
1.设置左边界left和右边界right。后续则需要调整他们两的区间进行二分查找。
int left = 0;
int right = nums.length-1;
2.mid是中间位置的下标,因为每一次缩小区间时left和right的值都改变,所以mid的值也会随之改变。因此我把mid的定义放在循环内。
while(left<=right){
int mid = (left+right)/2;
//......
}
3.判断中间位置的数是否为target,若是则直接返回下标mid,否则,继续后续判断。
if(target == nums[mid]){
return mid;
}
4.判断右边半段是否完全有序。若是完全有序,则继续判断target是否在区间内,若在,则对该区间继续二分查找,若不在该区间内则对另外的区间进行二分查找;
else if(nums[mid]<nums[right]){
if(nums[mid]<target && target<=nums[right]){
left = mid+1;
}else{
right = mid-1;
}
}
5.若左边半段是完全有序,则故技重施,与第4.的方法一样。
else{
if(nums[left]<=target && target<nums[mid]){
right = mid-1;
}else{
left = mid+1;
}
}
6.若循环结束后,仍然没有结束程序,即表面找不到target的值。返回-1即可。
return -1;