前言
代码随想录day1,皆为LeetCode题。
共4题,知识点如下。
二分:
704. 二分查找、
705. 搜索插入位置、
706. 在排序数组中查找元素的第一个和最后一个位置。
双指针:
708. 移除元素。
模版
二分
bool check(int x) {/* ... */} // 检查x是否满足某种性质
// 区间[l, r]被划分成[l, mid]和[mid + 1, r]时使用:
int bsearch_1(int l, int r)
{
while (l < r)
{
int mid = l + r >> 1;
if (check(mid)) r = mid; // check()判断mid是否满足性质
else l = mid + 1;
}
return l;
}
// 区间[l, r]被划分成[l, mid - 1]和[mid, r]时使用:
int bsearch_2(int l, int r)
{
while (l < r)
{
int mid = l + r + 1 >> 1;
if (check(mid)) l = mid;
else r = mid - 1;
}
return l;
}
r = mid
, 就不需要补上加一
若是l = mid
,那么前面是int mid = (l + r + 1)>> 1
教大家一个口诀 男左女右(判断为true时)
男是一 所以加一 女是零所以不用加
为什么要加1?
当l = r - 1的时候,如果不加1,mid = (2l + 1) / 2 = l
,
即没变,会死循环
双指针
for (int i = 0, j = 0; i < n; i ++ )
{
while (j < i && check(i, j)) j ++ ;
// 具体问题的逻辑
}
常见问题分类:
(1) 对于一个序列,用两个指针维护一段区间
(2) 对于两个序列,维护某种次序,比如归并排序中合并两个有序序列的操作
704. 二分查找
模版题
仅特判一下不等于target的时候返回-1即可
class Solution {
public:
int search(vector<int>& nums, int target) {
int l = 0, r = nums.size() - 1;
while (l < r) {
int mid = l + r >> 1; // 在mid左边
if (nums[mid] >= target) r = mid;
else l = mid + 1;
}
if (nums[r] != target) return -1;
return r;
}
};
35. 搜索插入位置
找到第一个大于等于当前数的位置,
x >= target
可以插入到最后一个位置的后面,所以令r = num.size();
mid 向下取整,一定会小于size
class Solution {
public:
int searchInsert(vector<int>& nums, int target) {
int l = 0, r = nums.size();
while (l < r) {
int mid = l + r >> 1;
if (nums[mid] >= target) r = mid;
else l = mid + 1;
}
return l;
}
};
34. 在排序数组中查找元素的第一个和最后一个位置
删掉注释能从16ms降到4ms,牛的
先找左边界,此时条件为nums[mid] >= target
,即第一个等于目标的位置
右边界条件为nums[mid] <= target
,即最后一个等于目标的位置
class Solution {
public:
vector<int> searchRange(vector<int>& nums, int target) {
// 容易忘
if (nums.empty()) return {-1, -1};
// 找左边界
int l = 0, r = nums.size() - 1;
while (l < r) {
int mid = l + r >> 1;
if (nums[mid] >= target) r = mid;
else l = mid + 1;
}
// 没找到
if (nums[r] != target) return {-1, -1};
// 更新左边界为l或者r都行,此时相等
int L = r;
// 找右边界
l = 0, r = nums.size() - 1;
while (l < r) {
int mid = l + r + 1 >> 1;
if (nums[mid] <= target) l = mid;
else r = mid - 1;
}
return {L, r};
}
};
27. 移除元素
例子
初始状况,上面的指针为指针1,下面的为指针2
指针1一直往后移,遍历所有值,所有值等于3的时候,指针2不变
刚开始值等于3,指针2不变,
当指针1移到值2时,指针2移动一位,此时数组为{2}
指针1又到3,指针2不变,指针1移到4的位置,指针2移动一位,此时数组为{2,4}
指针1移到值5,不等于3,指针2移动一位
最终数组值为{2,4,5}
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int k = 0;
for (int i = 0; i < nums.size(); i++)
if (nums[i] != val)
nums[k ++] = nums[i];
return k;
}
};