1. 注意计算mid时的整形溢出
  2. 边界值判断
  3. 数组必须时有序的
  4. 时间复杂度O(logn)
  5. 二分方式:二分下标,二分答案

1. 基本二分查找

局限性:无法查找target的左右侧边界

  1. int binarySearch(vector<int>& nums, int target)
  2. {
  3. int left = 0;
  4. int right = nums.size() - 1;
  5. while (left <= right) {
  6. int mid = (right - left) / 2 + left;
  7. if (nums[mid] == target) {
  8. return mid;
  9. } else if (nums[mid] < target) {
  10. left = mid + 1;
  11. } else if (nums[mid] > target) {
  12. right = mid - 1;
  13. }
  14. }
  15. return -1;
  16. }

2. 寻找左侧边界

  1. // 寻找数组中最左边的目标[1, 2, 2, 2, 3]中index = 1的2
  2. // [left, right]写法
  3. int binarySearch(vector<int>& nums, int target)
  4. {
  5. int left = 0;
  6. int right = nums.size() - 1;
  7. while (left <= right) {
  8. int mid = (right - left) / 2 + left;
  9. if (nums[mid] == target) {
  10. right = mid - 1; // 收缩右侧边界
  11. } else if (nums[mid] < target) {
  12. left = mid + 1;
  13. } else if (nums[mid] > target) {
  14. right = mid - 1;
  15. }
  16. }
  17. // 左侧边界的概念:nums小于target的个数有left个
  18. // left 可能是0,代表比target小的有0个
  19. // left 也可能是nums.size(),代表都比target小
  20. if (left >= nums.size() || nums[left] != target) {
  21. return -1;
  22. }
  23. return left;
  24. }

3. 寻找右侧边界

  1. // 寻找数组中最右边的目标[1, 2, 2, 2, 3]中index = 3的2
  2. // [left, right]写法
  3. int binarySearch(vector<int>& nums, int target)
  4. {
  5. int left = 0;
  6. int right = nums.size() - 1;
  7. while (left <= right) {
  8. int mid = (right - left) / 2 + left;
  9. if (nums[mid] == target) {
  10. left = mid + 1; // 收缩左侧边界
  11. } else if (nums[mid] < target) {
  12. left = mid + 1;
  13. } else if (nums[mid] > target) {
  14. right = mid - 1;
  15. }
  16. }
  17. // 右侧边界的概念:nums小于等于target的个数有right个
  18. // right 可能是nums.size() - 1,代表比target大的有0个
  19. // right 也可能是-1,代表都比target大
  20. if (right < 0 || nums[right] != target) {
  21. return -1;
  22. }
  23. return right;
  24. }

4. 二分查找函数

  1. #include <algorithm>
  2. vector<int> a = {1, 3, 3, 5, 7};
  3. vector<int>::iterator it = lower_bound(a.begin(), a.end(), 3); // index = 1, 查找有序区间a[i] >= k的最小指针
  4. vector<int>::iterator it = upper_bound(a.begin(), a.end(), 3); // index = 3, 查找有序区间a[i] > k的最小指针
  5. bool ret = binary_search(a.begin(), a.end(), 3); // ret = true, 查找有序区间是否存在val。
  6. // 注意查找区间:左闭右开,有序。适用于set\map\vector
  7. // 函数lower_bound()在first和last中的前闭后开区间进行二分查找,返回大于或等于val的第一个元素位置。如果所有元素都小于val,则返回last的位置,且last的位置是越界的!
  8. // 要计算下标pos,需要减去a.begin(),pos的可能值是[0, a.size()], 注意a.size()是越界的、代表所有值都比val小
  9. int pos = lower_bound(a.begin(), a.end(), 3) - a.begin();
  10. int b[5] = {1, 3, 3, 5, 7};
  11. int pos = lower_bound(b, b + 5, 3) - a;
  12. // 计算长度为n的有序数组a中k的个数,可以为0
  13. int num = upper_bound(a.begin(), a.end(), 3) - lower_bound(a.begin(), a.end(), 3);
  14. // 将有序数组a中k所对应位置的元素改为k;
  15. *lower_bound(a.begin(), a.end(), k) = k;
  16. // 查找第一个最大值/最小值的地址,有相同大小的元素,找第一个
  17. vector<int>::iterator it = max_element(a.begin(), a.end());
  18. vector<int>::iterator it = min_element(a.begin(), a.end());
  19. // 查找第一个最大值/最小值的下标
  20. int pos = max_element(a.begin(), a.end()) - a.begin();
  21. int pos = min_element(a.begin(), a.end()) - a.begin();
  22. // 查找第一个最大值/最小值
  23. int maxNum = *max_element(a.begin(), a.end());
  24. int minNum = *min_element(a.begin(), a.end());
  1. // 编写一个高效的算法来判断 m x n 矩阵中,是否存在一个目标值。该矩阵具有如下特性:
  2. // 每行中的整数从左到右按升序排列。
  3. // 每行的第一个整数大于前一行的最后一个整数。
  4. class Solution {
  5. public:
  6. // 将二维数组转化为一维数组的方式
  7. bool searchMatrix(vector<vector<int>>& matrix, int target) {
  8. int m = matrix.size();
  9. int n = matrix[0].size();
  10. int left = 0;
  11. int right = m * n - 1;
  12. while (left <= right) {
  13. int mid = (right - left) / 2 + left;
  14. if (matrix[mid / n][mid % n] == target) {
  15. return true;
  16. } else if (matrix[mid / n][mid % n] < target) {
  17. left = mid + 1;
  18. } else if (matrix[mid / n][mid % n] > target) {
  19. right = mid - 1;
  20. }
  21. }
  22. return false;
  23. }
  24. };