先说体会:
二分法中,无论是r=mid-1,还是l=mid+1;都说明mid不是我们要的答案,所以我们不要它,将它减去,或者略过。
如果是l=mid或者r=mid,说明mid还有用
以下为两个重要模板
二分法其实是不断逼近x,我们假设q[ ]数组是从小到大排列的
模板1:
while (l < r)
{
int mid = l + r >> 1;
if (q[mid] >= x) r = mid;//这个r可以用来求出来的是>=x的最小值(优先求出)
else l = mid + 1;
}
//如果不存在>=x的最小值,这个r求出来的是<=x的最大值(其次求出)
模板2
while (l < r)
{
int mid = l + r + 1 >> 1;
if (q[mid] <= x) l = mid;//这个l可以用来求出来的是<=x的最大值(优先求出)
else r = mid - 1;
}
//如果不存在<=x的最大值,这个l求出来的是>=x的最小值(其次求出)
2022-11-20的力扣320场周赛的第二题,完美的使用了以上的模板
6242. 二叉搜索树最近节点查询
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
vector<vector<int>> closestNodes(TreeNode* root, vector<int>& queries) {
if(!root)return{{-1,-1}};
vector<int>v;
vector<vector<int>>ans;
queue<TreeNode*> q;
q.push(root);
//下面这个while循环就是宽搜框架
while(q.size()){
int len = q.size();//这个一层的元素个数
for(int i = 0 ;i<len ;i++){
auto t = q.front();//每次拿到这个一行的第i个元素
v.push_back(t->val);
q.pop();
//接下来,我们来扩展一下队列,为下一层宽搜作准备
if(t->left)q.push(t->left);
if(t->right)q.push(t->right);
}
}
sort(v.begin(),v.end());//我们模拟的单调队列
for(int i = 0 ;i<queries.size();i++){
int l=0,r=v.size()-1;//队头和队尾
while(l<r){//求>=queries[i]的最小值
int mid = l + r >>1;
if(v[mid]>=queries[i])r=mid;
else l = mid +1;
}
int tmp = r;
l=0,r=v.size()-1;//队头和队尾
while(l<r){//求<=queries[i]的最大值
int mid = l + r +1 >>1;
if(v[mid]<=queries[i])l=mid;
else r = mid -1;
}
int left=v[l],right=v[tmp];
if(v[tmp]<queries[i])right = -1;
if(v[l]>queries[i])left = -1;
ans.push_back({left,right});
}
return ans;
}
};
再来一题
AcWing 789. 数的范围(算法基础课)
再来一题
LeetCode 33. 搜索旋转排序数组(LeetCode究极班)
再来一题
6367. 求出最多标记下标
再来一题
AcWing 1236. 递增三元组
补充