目录
- 二分查找
- 思想
- [704.二分查找 - 力扣](https://leetcode.cn/problems/binary-search/)
- [35.搜索插入位置 - 力扣](https://leetcode.cn/problems/search-insert-position/)
- [162.寻找峰值 - 力扣](https://leetcode.cn/problems/find-peak-element/)
- [34.在排序数组中查找元素的第一个和最后一个位置 - 力扣](https://leetcode.cn/problems/find-first-and-last-position-of-element-in-sorted-array/)
- [74.搜索二维矩阵 - 力扣](https://leetcode.cn/problems/search-a-2d-matrix/)
- [240.搜索二维矩阵 II - 力扣](https://leetcode.cn/problems/search-a-2d-matrix-ii/)
二分查找
二分查找是背板子的问题,但是经常出现细节处理很烦的问题,今天在b站发现了一个特别神奇的二分新思想。
思想
伪代码如上,在端点定义时这么定义,可以在l/r的处理上变得很方便,返回时根据需求即可,如此骚操作,拿题来试一下:
704.二分查找 - 力扣
我的代码不一定是最好的,本题是二分查找板子题,让我们来看一哈板子题是怎么写的:
class Solution {
public:
int search(vector<int>& nums, int target) {
int l = 0;
int r = nums.size();
int mid = 0;
while(l + 1 != r){
mid = l + (r - l) / 2;
if(nums[mid] == target){
return mid;
}else if(nums[mid] < target){
l = mid;
}else{
r = mid;
}
}
if(nums[l] == target){
return l;
}else{
return -1;
}
}
};
很舒服的代码,找不到目标的话,直接在结尾特判一下就好了,基本思想跟二分是一模一样的。
中等难度
35.搜索插入位置 - 力扣
也是一道简单题,这个直接返回r即可
class Solution {
public:
int searchInsert(vector<int>& nums, int target) {
int l = -1;
int r = nums.size();
int mid = 0;
while(l + 1 != r){
mid = l + (r - l) / 2;
if(nums[mid] < target){
l = mid;
}else{
r = mid;
}
}
return r;
}
};
162.寻找峰值 - 力扣
num[i] < nums[i+1] && nums[i] > nums[i-1] 说明峰值在其右边;
num[i] > nums[i+1] && nums[i] < nums[i-1] 说明峰值在其左边;
num[i] < nums[i+1] && nums[i] < nums[i-1] 说明在谷底,下一步往左边和右边都可以
简单借鉴了一下别人的代码,这道题需要特殊处理一下当数组只有很少数个的时候的情况
class Solution {
public:
int findPeakElement(vector<int>& nums) {
if(nums.size() <= 1)
return 0;
int l = -1;
int r = nums.size();
while(l + 1 != r){
int mid = l + (r - l) / 2;
int lvalue = mid - 1 < 0 ? -2147483648 : nums[mid - 1];
int rvalue = mid + 1 >= nums.size() ? -2147483648 : nums[mid + 1];
if(nums[mid] >= lvalue && nums[mid] <= rvalue){
l = mid;
}else{
r = mid;
}
}
return r;
}
};
力扣的测试样例有一组数据是[-2147483648,-2147483647],所以把lvalue和rlvalue的值设置为int的最小值。
34.在排序数组中查找元素的第一个和最后一个位置 - 力扣
class Solution {
public:
vector<int> searchRange(vector<int>& nums, int target) {
int l1 = -1;
int r1 = nums.size();
while(l1 + 1 != r1){
int mid = l1 + (r1 - l1) / 2;
if(nums[mid] < target){
l1 = mid;
}else{
r1 = mid;
}
}
int r2 = r1;
if (r1 == nums.size() || nums[r1] != target)
return vector<int>{-1,-1};
while(r2 + 1 < nums.size() && nums[r2 + 1] == target)
r2++;
return vector<int>{r1,r2};
}
};
代码太水了,但是需要注意的是,在第一次二分查找,把小于target的值直接全部放到左边,然后右指针就是要找的第一个数组下标,然后向后循环找到最后一个target即可,主语吼,最后一个while循环,条件那么写就行,然后就是,需要处理一下数组里面没有或者找完以后发现没有target时需要返回[1,-1]
74.搜索二维矩阵 - 力扣
class Solution {
public:
bool searchMatrix(vector<vector<int>>& matrix, int target) {
int m = matrix.size(), n = matrix[0].size();
if(matrix[m - 1][n - 1] < target) return false;
int l = -1;
int r = m * n;
while(l + 1 != r){
int mid = l + (r - l) / 2;
int i = mid / n;
int j = mid % n;
if(matrix[i][j] < target){
l = mid;
}else{
r = mid;
}
}
return matrix[r / n][r % n] == target;
}
};
这道题直接把二维矩阵转化成一维来看然后二分即可。
因为数组边界已知,所以在转化后的一维下标想得到原来的二维下标,把 mid 除以 n(列数),即可得到行数下标,把 mid 作 n (列数)的余数,即可得到列数,然后便可得到二维下标,判断是否小于target即可,最后找到的r便是target的一维下标,然后我们对照一下二维下标的数组中的值是否等于target然后输出即可。
240.搜索二维矩阵 II - 力扣
这个题跟上一道不太一样,使用这种二分搜索的话,或者像官网的二分搜索的话,较繁琐,而且也不能将其转换为一维数组进行思索,所以使用最简单的搜索,从右上角搜索,这样子只需要查找一行和一列就可以了
class Solution {
public:
bool searchMatrix(vector<vector<int>>& matrix, int target) {
int m = matrix.size(), n = matrix[0].size();
int i = 0, j = n - 1;
while(i < m && j >= 0){
if(matrix[i][j] > target){
j--;
}else if(matrix[i][j] < target){
i++;
}else{
return true;
}
}
return false;
}
};
因为数组的特点是,每一个元素的右侧或者下侧的元素都比它大,所以可以从右上角进行向下查找搜索。
这里需要注意一下 while 的判断条件,j 是可以等于零的。
目前就写了这些题,后续再加吧~