本文参考自https://leetcode-cn.com/problems/search-in-rotated-sorted-array/solution/yi-wen-dai-ni-shua-bian-er-fen-cha-zhao-dtadq/
二分查找
在计算机科学中,二分搜索(binary search),也称折半搜索(half-interval search)、对数搜索(logarithmic search),是一种在有序数组中查找某一特定元素的搜索算法。
搜索过程从数组的中间元素开始,如果中间元素正好是要查找的元素,则搜索过程结束;如果某一特定元素大于或者小于中间元素,则在数组大于或小于中间元素的那一半中查找,而且跟开始一样从中间元素开始比较。如果在某一步骤数组为空,则代表找不到。这种搜索算法每一次比较都使搜索范围缩小一半。
模式识别:对于有序数组或者部分有序数组,基本使用二分搜索及其变种
算法描述:”丢弃“一半的数据
时间复杂度: O(logn)
二分查找模板
def binarySearch(nums:list,target:int) -> int:
l,r = 0,len(nums)-1
while l<=r: #注意 = ,因为我们要找的值可能刚好就是两者重合的时候
mid = (l+r)//2
if nums[mid] == target:
return mid
elif nums[mid] > target:
r = mid - 1 #注意-1,否则可能死循环
else:
l = mid + 1 #注意+1,否则可能死循环
return -1
LeetCode 33. 搜索旋转排序数组
整数数组 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
。
示例 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
-10^4 <= nums[i] <= 10^4
nums
中的每个值都 独一无二- 题目数据保证
nums
在预先未知的某个下标上进行了旋转 -10^4 <= target <= 10^4
上图的数组虽然不是完全有序,但是可以看成两个完全独立的有序数组,故属于一种变种的二分查找。
二分查找中必定会求mid,所以我们来分析一下mid的情况:
我们将两个独立的有序数组称为数组1和数组2,如上图所示。mid无非就两种情况,一种是跟left处于同一个有序数组里,另一种是跟right处于同一个有序数组里。现在我们来讨论mid与left在同一个有序数组的情况:
此时,target的值要么落在nums[left]与nums[mid]之间(nums[left]<=target<nums[mid]),要么落在nums[mid]与nums[right]之间(nums[mid]<target<=nums[right])。显然如果是属于前者情况,那么该问题就回归到一个普通的二分查找。那如果是后者呢?我们直接将mid+1的值赋给right那么就转到数组2中进行普通的二分查找了。mid与right在同一个有序数组的情况下我们可以如法炮制。
综上,我们可以写出如下代码:
def search(nums:list,target:int)->int:
left,right = 0,len(target)-1
while left<=right:
mid = (left+right)//2
if nums[mid]==target:
return mid
if nums[mid]>=nums[left]:
if nums[left]<=target<nums[mid]:
right = mid - 1
else:
left = mid + 1
else:
if nums[mid]<target<nums[right]:
left = mid + 1
else:
right = mid - 1
return -1