目录
二分算法
算法模板
等值问题模板:
1. 闭区间求法模板
2. 左闭右开区间模板
区间问题模板
1. 闭区间求法模板
2. 左闭右开区间模板
LeeCode704. Binary Search
LeeCode35. Search Insert Position
LeeCode34. Find First and Last Position of Element in Sorted Array
双指针
LeeCode27.Remove Element
二分算法分为两种大类别:等值类型和区间类型
public:
int searchInsert(vector& nums, int target) {
// 闭区间
int l = 0, r = nums.size() - 1;
while (l <= r) {
int mid = (r - l) / 2 + l;
if (nums[mid] == target) return mid;
else if (nums[mid] > target) r = mid - 1;
else l = mid + 1;
}
return l;
}
public:
int searchInsert(vector& nums, int target) {
// 左闭右开
int l = 0, r = nums.size();
while (l < r) {
int mid = (r - l) / 2 + l;
if (nums[mid] == target) return mid;
else if (nums[mid] > target) r = mid;
else l = mid + 1;
}
return l;
}
public:
int getStart(vector& nums, int target) {
// 采用闭区间写法获得第一次出现的位置
int n = nums.size();
int l = 0, r = n - 1;
while (l <= r) {
int mid = (r - l) / 2 + l;
// 接下来寻找的区间:[mid + 1 , r]
if (nums[mid] < target) l = mid + 1;
// 包含nums[mid] == target的情况,由于要寻找第一次出现的位置,所以就算找到了,也要继续向左寻找 接下来寻找的区间:[l, mid - 1]
else r = mid - 1;
}
return l;
}
public:
int getStart1(vector& nums, int target) {
// 采用左闭右开区间写法获得第一次出现的位置
int n = nums.size();
int l = 0, r = n;
while (l < r) {
int mid = (r - l) / 2 + l;
// 接下来寻找的区间:[mid + 1, r)
if (nums[mid] < target) l = mid + 1;
// 接下来寻找的区间:[l, mid)
else r = mid;
}
return l;
}
题目地址:704
题目类型:二分等值问题
思路:一个很标准的闭区间等值问题,直接AC。
class Solution {
public:
// 一个升序排列的数组nums
int search(vector& nums, int target) {
int l = 0, r = nums.size() - 1;
// 此处要加上一个等号,因为要考虑到nums长度为1的情况
while (l <= r) {
int mid = (r - l) / 2 + l;
if (nums[mid] == target) return mid;
else if (nums[mid] < target) l = mid + 1;
else r = mid - 1;
}
return -1;
}
};
题目地址:力扣
题目类型:二分等值问题
思路:寻找插入位置等价于寻找target应当在数组中出现的位置,即等值问题,可以采用闭区间和左闭右开区间两种方法求解。
1. 闭区间解法
class Solution {
public:
int searchInsert(vector& nums, int target) {
// 闭区间
int l = 0, r = nums.size() - 1;
while (l <= r) {
int mid = (r - l) / 2 + l;
if (nums[mid] == target) return mid;
else if (nums[mid] > target) r = mid - 1;
else l = mid + 1;
}
return l;
}
};
2. 左闭右开区间解法
class Solution {
public:
int searchInsert(vector& nums, int target) {
// 左闭右开
int l = 0, r = nums.size();
while (l < r) {
int mid = (r - l) / 2 + l;
if (nums[mid] == target) return mid;
else if (nums[mid] > target) r = mid;
else l = mid + 1;
}
return l;
}
};
题目地址:力扣
题目类型:二分区间问题
思路:本题一共需要求两个值:
看似需要分别来求以上两个子问题,实际上当求出≥ target,直接使用 ≤ (≥ target+1) - 1 即可。
故直接编写求解子问题1的函数getStart(nums, target),使start = getStart(nums, target),使end = getStart(nums, target + 1) - 1。
class Solution {
private:
// getStart方法对应的都是求>=target的边界值
int getStart(vector& nums, int target) {
// 采用闭区间写法获得starting position
int n = nums.size();
int l = 0, r = n - 1;
while (l <= r) {
int mid = (r - l) / 2 + l;
// [mid + 1 , r]
if (nums[mid] < target) l = mid + 1;
// 包含nums[mid] == target的情况,由于要寻找第一次出现的位置,所以就算找到了,也要继续向左寻找 [l, mid - 1]
else r = mid - 1;
}
return l;
}
int getStart1(vector& nums, int target) {
// 采用左闭右开区间写法获得starting position
int n = nums.size();
int l = 0, r = n;
while (l < r) {
int mid = (r - l) / 2 + l;
// [mid + 1, r]
if (nums[mid] < target) l = mid + 1;
else r = mid;
}
return l;
}
public:
vector searchRange(vector& nums, int target) {
// start是>=target的边界值, end是<=target的边界值,end即求:>=target + 1对应的start,然后<= start - 1
int start, end;
start = getStart(nums, target);
if (start == nums.size() || nums[start] != target) return {-1, -1};
end = getStart1(nums, target + 1) - 1;
return {start, end};
}
};
题目地址:力扣
题目类型:双指针
思路:要使用O(n)的时间复杂度实现原地修改数组,第一眼要想到的就是上指针,没什么好说的,很标准很简单的一道题,直接AC。
class Solution {
public:
int removeElement(vector& nums, int val) {
// i和j代表左右指针,count用于计数
int i = 0, j = 0, count = 0;
while (j < nums.size()) {
if (nums[j] != val) {
swap(nums[i], nums[j]);
i++;j++;
}
else {
j++;
count++;
}
}
return nums.size() - count;
}
};
第一次认真写博客,大概写了一两个小时,希望对有需要的人能有所帮助,这次的训练也让我对binary search有了更加透彻的理解,不过也深知还有许多未能探讨的到的地方,继续努力。