刷题 二分查找

二分查找

二分查找的本质就是 缩小有效范围

需要注意:

  • int mid = (left + right) / 2; int mid = left + (right - left) / 2; 防止溢出

hot100 - 二分查找

⭐️35. 搜索插入位置

找到第一个大于等于 target 的值

cpp 复制代码
class Solution {
public:
    // 目标: 找到第一个大于等于 target 的值
    int searchInsert(vector<int>& nums, int target) {
        int left = 0, right = nums.size() - 1;
        while (left <= right) { // 区间不为空
            // 区间缩减的循环不变量
            // nums[left - 1] < target
            // nums[right + 1] >= target
            int mid = left + (right - left) / 2;
            if (nums[mid] < target) {
                left = mid + 1;     // 缩小范围到 [mid + 1, right]
            } else {
                right = mid - 1;    // 缩小范围到 [left, mid - 1]
            }
        }
        return left;
    }
};
cpp 复制代码
class Solution {
public:
    // 目标: 找到第一个大于等于 target 的值
    int searchInsert(vector<int>& nums, int target) {
        int left = 0, right = nums.size();
        while (left < right) { // 区间不为空
            // 区间缩减的循环不变量
            // nums[left - 1] < target
            // nums[right] >= target
            int mid = left + (right - left) / 2;
            if (nums[mid] < target) {
                left = mid + 1;     // 缩小范围到 [mid + 1, right]
            } else {
                right = mid;    // 缩小范围到 [left, mid - 1]
            }
        }
        return left;
    }
};

74. 搜索二维矩阵

cpp 复制代码
class Solution {
public:
    // 二分法的核心:缩小有效区间
    bool searchMatrix(vector<vector<int>>& matrix, int target) {
        int n = matrix.size(), m = matrix[0].size();
        if (target < matrix[0][0] || target > matrix[n - 1][m - 1]) return false;

        int left = 0, right = n - 1, row = 0, col = 0;
        
        // 二分查找,先确定在哪一行
        while (left <= right) {
            // 循环不变量
            // nums[left-1][m-1] < target
            // nums[right+1][m-1] > target
            row = left + (right - left) / 2;
            if (matrix[row][m - 1] == target) {
                return true;
            } else if (matrix[row][m - 1] < target) {
                left = row + 1;
            } else {
                right = row - 1;
            }
        }
        // 循环结束
        row = left;

        // 二分查找,再确定在哪一列
        left = 0, right = m - 1;
        while (left <= right) {
            // 循环不变量
            // nums[row][left-1] < target
            // nums[row][right+1] > target
            col = left + (right - left) / 2;
            if (matrix[row][col] == target) {
                return true;
            } else if (matrix[row][col] < target) {
                left = col + 1;
            } else {
                right = col - 1;
            }
        }
        return false;
    }
};

⭐️⭐️⭐️162. 寻找峰值


cpp 复制代码
class Solution {
public:
    // 首先我们可以判定,数组中必然包含至少一个峰值元素
    // 峰值元素的特征 nums[i] > nums[i-1] nums[i] > nums[i + 1]
    // 相当于找极大值点
    int findPeakElement(vector<int>& nums) {
        int n = nums.size();
        int left = 0, right = n - 1;
        while (left < right) {
            int mid = left + (right - left) / 2;
            if ((mid == 0 || nums[mid] > nums[mid - 1]) && (mid != n - 1 && nums[mid] < nums[mid + 1])) {
                left = mid + 1;
            } else if ((mid != 0 && nums[mid] < nums[mid - 1]) && (mid == n - 1 || nums[mid] > nums[mid + 1])) {
                right = mid - 1;
            } else if ((mid == 0 || nums[mid] > nums[mid - 1]) && (mid == n - 1 || nums[mid] > nums[mid + 1])) {
                return mid;
            } else {
                // 以下两种都可以
                left = mid + 1;
                // right = mid - 1;
            }
        }
        return left;
    }
};

代码优化

严格证明,简洁写法(Python/Java/C++/C/Go)

cpp 复制代码
class Solution {
public:
    // 首先我们可以确定必然有一个峰值, 因此我们只需要进行区间缩减即可
    int findPeakElement(vector<int>& nums) {
        int left = 0, right = nums.size() - 1;
        while (left < right) {
            int mid = left + (right - left) / 2;
            if (nums[mid] < nums[mid + 1]) {    // 如果 nums[mid] < nums[mid + 1],说明右侧有峰值
                left = mid + 1;
            } else {                            // nums[mid] > nums[mid + 1], 说明左侧有峰值
                right = mid;
            }
        }
        // left == right 时即为峰值位置
        return left;
    }
};

33. 搜索旋转排序数组

看清楚题意,是将一个升序序列旋转一下,不是两个升序序列拼在一起

cpp 复制代码
class Solution {
public:
    int search(vector<int>& nums, int target) {
        int n = nums.size(), left = 0, right = n - 1;
        while (left <= right) {
            int mid = left + (right - left) / 2;
            if (target == nums[mid]) {
                return mid;
            } else {
                if (nums[mid] >= nums[0]) { // 在第一个上升区间 nums[mid] >= nums[0]
                    if (target > nums[mid] || target < nums[0]) left = mid + 1;
                    else right = mid - 1;
                } else { // 在第二个上升区间 nums[mid] < nums[0]
                    if (target < nums[mid] || target > nums[n - 1]) right = mid - 1;
                    else left = mid + 1;
                }
            }
        }
        return -1;
    }
};

34. 在排序数组中查找元素的第一个和最后一个位置

153. 寻找旋转排序数组中的最小值

4. 寻找两个正序数组的中位数

相关推荐
九英里路7 分钟前
protobuf快速上手
网络·c++·中间件·json·谷歌·序列化·protobuf
纪念 2291 小时前
C++ 算法基础 (差分)
开发语言·c++·算法
ShineWinsu6 小时前
对于Qt:QTreeWidget常见属性以及QTreeWidgetItem类的解析
开发语言·c++·qt·gui·客户端·多叉树·qtreewidget
落羽的落羽6 小时前
【C++】C++17的主要特性
linux·服务器·开发语言·c++·算法·机器学习
汉克老师12 小时前
《从C++小白到算法高手:GESP 1—8级成长地图》第一讲:认识GESP——从编程新手到算法探索者
c++·gesp·信息学竞赛·小学生学c++
晴天的雨.99213 小时前
【C++】继承篇
java·开发语言·c++
青少儿编程课堂13 小时前
蓝桥杯青少组图形化 + 全国青少年信息素养大赛 + 电子学会图形化考级:校园大富翁经营闯关解析
c++·python·算法·bfs·信息学竞赛
another heaven13 小时前
【C/C++ 第一次跨越(上):用 C++11/14 停止制造新的旧代码】
c语言·c++·制造
qq_4069810313 小时前
c++ lamda(三)Lambda表达式
java·前端·c++
I_belong_to_jesus1 天前
C++关于分支预测的优化1
开发语言·c++·算法