二分查找
0. 模板
判断左闭右开区间 = [left, mid, right)
def binary_search(left, right):
while left < right:
mid = left + (right - l) // 2
if isResult(mid): return mid
if judge(mid):
right = mid # next range = [l, m)
else:
left = mid + 1 # next range = [m+1, r)
return left
1. 求开方
思路:while循环条件为left <= right
,一般情况思路很清晰,这里主要主要边界情况。当while退出循环的时候,一定有left > right
,以8为例子,此时left为3,right为2,应当返回right。(边界情况,往往是二分查找需要注意的地方)
# Python
class Solution:
def mySqrt(self, x: int) -> int:
if x <= 1: return x
left, right = 1, x
while left <= right:
mid = (left + right) // 2
if mid ** 2 > x:
right = mid - 1
elif mid ** 2 < x:
left = mid + 1
else:
return mid
return right
# C++
class Solution {
public:
int mySqrt(int x) {
if (x <= 1) return x;
long int left = 1, right = x;
while (left <= right) {
long int mid = (left + right) / 2;
if (mid * mid > x)
right = mid - 1;
else if (mid * mid < x)
left = mid + 1;
else
return mid;
}
return right;
}
};
2. 大于给定元素的最小元素
LeetCode 744. Find Smallest Letter Greater Than Target (Easy)
方法一:直接比较,时间复杂度 O ( n ) O(n) O(n)
方法二:二分搜索,时间复杂度 O ( log n ) O(\log n) O(logn)
# Python
# 方法一
class Solution:
def nextGreatestLetter(self, letters: List[str], target: str) -> str:
if letters[-1] <= target: return letters[0]
for item in letters:
if item > target:
return item
# 方法二
class Solution:
def nextGreatestLetter(self, letters: List[str], target: str) -> str:
if letters[-1] <= target: return letters[0]
left, right = 0, len(letters) - 1
while left <= right:
mid = (left + right) // 2
if letters[mid] > target:
right = mid - 1
else:
left = mid + 1
return letters[left]
# C++
class Solution {
public:
char nextGreatestLetter(vector<char>& letters, char target) {
if (letters[letters.size()-1] <= target) return letters[0];
int left = 0, right = letters.size() - 1;
while (left <= right) {
int mid = (left + right) / 2;
if (letters[mid] > target)
right = mid - 1;
else
left = mid + 1;
}
return letters[left];
}
};
3. 有序数组的Single Element
LeetCode 540. Single Element in a Sorted Array (Medium)
观察案例:
nums: 1 1 2 2 3 3 (4) 5 5 6 6
index: 0 1 2 3 4 5 (6) 7 8 9 10
单独出现的数字为4,4之前成对出现,4之后也成对出现。4之前的数对有index为奇数,对应的是后面的数,index为偶数,对应的是前面的数(一对数的前后)。4之后的数对则刚好相反。利用该条件可以判断,当前数是处于4的前面还是后面。利用此思想进行二分查找。
# Python
class Solution:
def singleNonDuplicate(self, nums: List[int]) -> int:
left, right = 0, len(nums)-1
while left < right:
mid = (left + right) // 2
if mid % 2 == 1: mid -= 1
if nums[mid] == nums[mid+1]:
left = mid + 2
else:
right = mid
return nums[left]
# C++
class Solution {
public:
int singleNonDuplicate(vector<int>& nums) {
int left = 0, right = nums.size() - 1;
while (left < right) {
int mid = (left + right) / 2;
if (mid % 2 == 1)
mid--;
if (nums[mid] == nums[mid+1])
left = mid + 2;
else
right = mid;
}
return nums[left];
}
};
4. 发现第一个错误版本
LeetCode 278. First Bad Version (Easy)
# Python
# The isBadVersion API is already defined for you.
# @param version, an integer
# @return an integer
# def isBadVersion(version):
class Solution:
def firstBadVersion(self, n):
"""
:type n: int
:rtype: int
"""
left, right = 0, n
while left <= right:
mid = (left + right) // 2
if isBadVersion(mid):
right = mid - 1
else:
left = mid + 1
return left
# C++
# The API isBadVersion is defined for you.
# bool isBadVersion(int version);
class Solution {
public:
int firstBadVersion(int n) {
long int left = 0, right = n;
while (left <= right) {
int mid = (left + right) / 2;
if (isBadVersion(mid))
right = mid - 1;
else
left = mid + 1;
}
return left;
}
};
5. 寻找升序数组的旋转点
LeetCode 153. Find Minimum in Rotated Sorted Array (Medium)
方法一:遍历数组,分别讨论只有一个元素,和数组为生序序列的情况,时间复杂度 O ( n ) O(n) O(n)
方法二:二分搜索,时间复杂度 O ( log n ) O(\log n) O(logn)
# Python 方法一
class Solution:
def findMin(self, nums: List[int]) -> int:
if len(nums) == 1: return nums[0]
for i in range(1, len(nums)):
if nums[i] > nums[i-1]:
continue
else:
return nums[i]
return nums[0]
# Python 方法二
class Solution:
def findMin(self, nums: List[int]) -> int:
left, right = 0, len(nums)-1
while left < right:
mid = (left + right) // 2
if nums[mid] <= nums[right]:
right = mid
else:
left = mid + 1
return nums[left]
# C++ 方法二
6. 在升序序列中寻找某一值的区间
LeetCode 34. Find First and Last Position of Element in Sorted Array (Medium)
# Python
class Solution:
def searchRange(self, nums: List[int], target: int) -> List[int]:
if not nums: return [-1, -1]
left, right = 0, len(nums)-1
while left < right:
mid = (left + right) // 2
if nums[mid] == target:
return self.findBoundary(nums, mid)
if nums[mid] < target:
left = mid + 1
else:
right = mid
if nums[left] == target:
return [left, left]
else:
return [-1, -1]
def findBoundary(self, nums, position):
left = right = position
while left > 0 and nums[left] == nums[left-1]:
left -= 1
while right < len(nums)-1 and nums[right] == nums[right+1]:
right += 1
return [left, right]
# C++