二分查找
寻找一个数(基本的二分搜索) 因为我们初始化 right = nums.length - 1 所以决定了我们的「搜索区间」是 [left, right] 所以决定了 while (left <= right),同时也决定了 left = mid+1 和 right = mid-1
因为我们只需找到一个 target 的索引即可,所以当 nums[mid] == target 时可以立即返回 | int binarySearch(vector<int> nums,int key){ int left=0,right=nums.size()-1; //** while(left<=right){ //** int mid=left+(right-left)/2; if(nums[mid]<key) left=mid+1; else if(nums[mid]>key) right=mid-1; else return mid; } return -1; } |
寻找左侧边界的二分搜索 因为我们初始化 right = nums.length 所以决定了我们的「搜索区间」是 [left, right) 所以决定了 while (left < right) 同时也决定了 left = mid+1 和 right = mid
因为我们需找到 target 的最左侧索引 所以当 nums[mid] == target 时不要立即返回 而要收紧右侧边界以锁定左侧边界 | int binarySearchFirst(vector<int> nums,int key){ int left=0,right=nums.size(); //** while(left<right){ //** int mid=left+(right-left)/2; if(nums[mid]>=key){ right=mid; }else left=mid+1; } return left; } |
寻找右侧边界的二分查找 因为我们初始化 right = nums.length 所以决定了我们的「搜索区间」是 [left, right) 所以决定了 while (left < right) 同时也决定了 left = mid+1 和 right = mid
因为我们需找到 target 的最右侧索引 所以当 nums[mid] == target 时不要立即返回 而要收紧左侧边界以锁定右侧边界 又因为收紧左侧边界时必须 left = mid + 1 所以最后无论返回 left 还是 right,必须减一 | int binarySearchLast(vector<int> nums,int key){ int left=0,right=nums.size(); while(left<right){ //** int mid=left+(right-left)/2; if(nums[mid]<=key){ left=mid+1; }else right=mid; } return left-1; } //相当于查找第一个>key的下标,然后-1。 |
二分查找(2.15) |
|
|
1. 求开方 | 一开始未做出,多种解法 | ※ |
2. 大于给定元素的最小元素 | 类上,Ok |
|
3. 有序数组的 Single Element | Ok,二分法思考后做出 | ※ |
4. 第一个错误的版本 | Ok |
|
5. 旋转数组的最小数字 | 一开始未做出 | ※ |
6. 查找区间 | 一次修改后ok |
|
1. 求开方
69. Sqrt(x) (Easy)
https://leetcode-cn.com/problems/sqrtx/submissions/
- 二分法:查找最后一个数满足(mid*mid<=n),即查找第一个数满足mid*mid>n然后-1。
class Solution { public: int mySqrt(int x) { if(x<0) return -1; else if(x==0||x==1) return x; int left=1,right=x; while(left<right){ int mid=left+(right-right)/2; if(x/mid>=mid) left=mid+1; else right=mid; } return left-1; } }; //查找第一个>x,然后-1
- 袖珍计算机算法:时间复杂度O(1),空间复杂度O(1)
class Solution {
public:
int mySqrt(int x) {
if(x<=1) return x;
int left=exp(0.5*log(x));
int right=left+1;
if(x/right<right) return left;
else return right;
}
};
3. 递归:时间复杂度O(logN),空间复杂度O(logN)
class Solution {
public:
int mySqrt(int x) {
if(x<=1) return x;
int left=mySqrt(x>>2)<<1;
int right=left+1;
if(x/right<right) return left;
else return right;
}
};
4. 牛顿法:时间复杂度O(logN),空间复杂度O(1)
class Solution {
public:
int mySqrt(int x) {
if(x<=1) return x;
double x0=x;
double x1=(x0+x/x0)/2;
while(abs(x1-x0)>=1){
x0=x1;
x1=(x0+x/x0)/2;
}
return (int)x1;
}
};
2. 大于给定元素的最小元素
744. Find Smallest Letter Greater Than Target (Easy)
https://leetcode-cn.com/problems/find-smallest-letter-greater-than-target/submissions/
类上,查找第一个大于给定元素
3. 有序数组的 Single Element
540. Single Element in a Sorted Array (Medium)
https://leetcode-cn.com/problems/single-element-in-a-sorted-array/
1. 异或
class Solution {
public:
int singleNonDuplicate(vector<int>& nums) {
int res=0;
for(int i=0;i<nums.size();i++)
res^=nums[i];
return res;
}
};
2. 二分排序
class Solution {
public:
int singleNonDuplicate(vector<int>& nums) {
int n=nums.size();
int left=0,right=n-1;
while(left<=right){
int mid=(left+right)/2;
bool isEven=mid%2;
if(mid+1<n&&nums[mid]==nums[mid+1]){
if(isEven) right=mid-1;
else left=mid+2;
}else if(mid-1>=0&&nums[mid]==nums[mid-1]){
if(isEven) left=mid+1;
else right=mid-2;
}else return nums[mid];
}
return nums[right];
}
};
4. 第一个错误的版本
278. First Bad Version (Easy)
https://leetcode-cn.com/problems/first-bad-version/
*找中间数用int mid=left+(right-left)/2;
5. 旋转数组的最小数字
153. Find Minimum in Rotated Sorted Array (Medium)
https://leetcode-cn.com/problems/find-minimum-in-rotated-sorted-array/
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]) right=mid;
else left=mid+1;
}
return nums[left];
}
};
//找第一个小于右边
6. 查找区间
34. Find First and Last Position of Element in Sorted Array
https://leetcode-cn.com/problems/find-first-and-last-position-of-element-in-sorted-array/
一次修改后ok