69. x 的平方根
- 二分查找即可,其中mid的平方可能会超出int的类型,所以转成long long 在比较,由于left+1,可能会去除正确结果,最后在核实一下即可
class Solution {
public:
int mySqrt(int x) {
int left = 0, right = x;
while(left < right){
int mid = (right + left) / 2;
if((long long)mid * mid == x)
return mid;
else if((long long)mid * mid > x)
right = mid - 1;
else
left = mid + 1;
}
if((long long)left * left > x)
left--;
return left;
}
};
744. 寻找比目标字母大的最小字母
- 给定一个有序的字符数组 letters 和一个字符 target,要求找出 letters 中大于 target 的最小字符,如果找不到就返回第 1 个字符。
class Solution {
public:
char nextGreatestLetter(vector<char>& letters, char target) {
int left = 0, right = letters.size() - 1;
if(letters[right] <= target)
return letters[0];
while(left <= right){
int mid =left + (right - left) / 2;
if(letters[mid] > target)
right = mid-1;
else
left = mid+1;
}
return letters[left];
}
};
540. 有序数组中的单一元素
- 要求以 O(logN) 时间复杂度进行求解,因此不能遍历数组并进行异或操作来求解,这么做的时间复杂度为 O(N)。
- 因为只有一个单的,所以我们只需要对偶数索引进行二分搜索即可。如果 nums[m] == nums[m + 1],那么 index 所在的数组位置为 [m + 2, r],此时令 l = m + 2;如果 nums[m] != nums[m + 1],那么 index 所在的数组位置为 [l, m],此时令 r = m。由于采用r = m的赋值形式,所以循环条件为l<r;
class Solution {
public:
int singleNonDuplicate(vector<int>& nums) {
int left = 0, right = nums.size() - 1;
while(left < right){
int mid = left + (right - left) / 2;
if(mid % 2 == 1)
mid--;
if (nums[mid] == nums[mid + 1])
left = mid + 2;
else
right = mid;
}
return nums[left];
}
};
278. 第一个错误的版本
- 如果第 m 个版本出错,则表示第一个错误的版本在 [l, m] 之间,令 h = m;否则第一个错误的版本在 [m + 1, h] 之间,令 l = m + 1。
- 因为 h 的赋值表达式为 h = m,因此循环条件为 l < h。
// The API isBadVersion is defined for you.
// bool isBadVersion(int version);
class Solution {
public:
int firstBadVersion(int n) {
int left = 1 ,right = n;
while(left < right){
int mid = left + (right -left) / 2;
if(isBadVersion(mid) == true)
right = mid;
else
left = mid + 1 ;
}
return left;
}
};
153. 寻找旋转排序数组中的最小值
- 如果nums[mid] > nums[right],则表示index在 [mid + 1,right] 之间,令 left = mid + 1;否则在 [left, mid] 之间,令 right = mid。
- 因为right的赋值表达式为 right = mid。因此循环条件为 left < right。
class Solution {
public:
int findMin(vector<int>& nums) {
int left = 0 , right = nums.size() - 1;
while(left < right){
int mid = left + (right - left) / 2;
if(nums[mid] > nums[right])
left = mid + 1;
else
right = mid;
}
return nums[left];
}
};
34. 在排序数组中查找元素的第一个和最后一个位置
-
可以用二分查找找出第一个位置和最后一个位置,但是寻找的方法有所不同,需要实现两个二分查找。我们将寻找 target 最后一个位置,转换成寻找 target+1 第一个位置,再往前移动一个位置。这样我们只需要实现一个二分查找代码即可。
-
我们的查找函数只能返回target可能在数组中的位置,并不保证该target一定存在数组中,所以判断时要加以判断。
-
在寻找第一个位置的二分查找代码中,需要注意 h 的取值为 nums.length,而不是 nums.length - 1。先看以下示例:
nums = [2,2], target = 2
- 如果 h 的取值为 nums.length - 1,那么 last = findFirst(nums, target + 1) - 1 = 1 - 1 = 0。这是因为 findLeft 只会返回 [0, nums.length - 1] 范围的值,对于 findFirst([2,2], 3) ,我们希望返回 3 插入 nums 中的位置,也就是数组最后一个位置再往后一个位置,即 nums.length。所以我们需要将 h 取值为 nums.length,从而使得 findFirst返回的区间更大,能够覆盖 target 大于 nums 最后一个元素的情况。
class Solution {
public:
vector<int> searchRange(vector<int>& nums, int target) {
int first = findFirst(nums,target);
int last = findFirst(nums,target+1) - 1;
if(first == nums.size() ||nums[first] != target ){
return vector<int> {-1 , -1};
}else{
return vector<int>{first,max(first,last)};
}
}
int findFirst(vector<int>& nums, int target){
int l = 0 ,r = nums.size();
while(l < r){
int m = l + (r - l) / 2;
if(nums[m] < target)
l = m + 1;
else
r = m;
}
return l;
}
};