万隆的笔记 万隆的笔记
博文索引
笔试面试
  • 在线学站

    • 菜鸟教程 (opens new window)
    • 入门教程 (opens new window)
    • Coursera (opens new window)
  • 在线文档

    • w3school (opens new window)
    • Bootstrap (opens new window)
    • Vue (opens new window)
    • 阿里开发者藏经阁 (opens new window)
  • 在线工具

    • tool 工具集 (opens new window)
    • bejson 工具集 (opens new window)
    • 文档转换 (opens new window)
  • 更多在线资源
  • Changlog
  • Aboutme
GitHub (opens new window)
博文索引
笔试面试
  • 在线学站

    • 菜鸟教程 (opens new window)
    • 入门教程 (opens new window)
    • Coursera (opens new window)
  • 在线文档

    • w3school (opens new window)
    • Bootstrap (opens new window)
    • Vue (opens new window)
    • 阿里开发者藏经阁 (opens new window)
  • 在线工具

    • tool 工具集 (opens new window)
    • bejson 工具集 (opens new window)
    • 文档转换 (opens new window)
  • 更多在线资源
  • Changlog
  • Aboutme
GitHub (opens new window)
  • 数据结构与算法

    • 基础数据结构
    • 算法基本知识
    • 时间复杂度
    • 时间复杂度拓展
    • 排序算法
    • 二分法
      • 二分查找
      • 非必要条件-有序
    • 异或运算
    • 链表结构基础
    • 栈和队列
    • 递归
    • 哈希表和有序表
    • 其他
  • 设计模式

  • 编程方法论

  • 分布式设计与微服务理论

  • Leetcode

  • 程序员内功
  • 数据结构与算法
2022-02-03
目录

二分法

# 二分法

# 二分查找

二分查找,也称为折半法,是一种在有序数组中查找特定元素的搜索算法。

二分法查找的思路如下:

  1. 首先,从数组的中间元素开始搜索,如果该元素正好是目标元素,则搜索过程结束,否则执行下一步。
  2. 如果目标元素大于/小于中间元素,则在数组大于/小于中间元素的那一半区域查找,然后重复步骤1的操作。
  3. 如果某一步,数组没有输进行查找,则表示找不到目标元素。

时间复杂度:O(log2n)O(log_{2}n)O(log2​n)

例如以下问题,都可以用二分法解决:

  1. 在一个有序数组中,找某个数是否存在。
public static boolean bsExist(int[] sortedArr, int num) {
  if (sortedArr == null || sortedArr.length == 0) {
    return false;
  }
  int L = 0;
  int R = sortedArr.length - 1;
  int mid = 0;
  // L..R 至少两个数的时候
  while (L < R) { 
    // 这种写法更安全
    mid = L + ((R - L) >> 1);
    if (sortedArr[mid] == num) {
      return true;
    } else if (sortedArr[mid] > num) {
      R = mid - 1;
    } else {
      L = mid + 1;
    }
  }
  return sortedArr[L] == num;
}

PS:常见技巧写法,n >> 1 等于 n/2 ,n << 1 等于 n * 2 ,( n << 1 )+ 1 等于 ( n << 1 )| 1

  1. 在一个有序数组中,找>=某个数最左侧的位置
public static int bsNearLeft(int[] arr, int value) {
  int L = 0;
  int R = arr.length - 1;
  // 记录最左的位置
  int index = -1;
  // L..R 至少一个数的时候
  while (L <= R) {
    int mid = L + ((R - L) >> 1);
    if (arr[mid] >= value) {
      index = mid;
      R = mid - 1;
    } else {
      L = mid + 1;
    }
  }
  return index;
}
  1. 在一个有序数组中,找>=某个数最右侧的位置
public static int bsNearRight(int[] arr, int value) {
  int L = 0;
  int R = arr.length - 1;
  // 记录最右的位置
  int index = -1;
  while (L <= R) {
    int mid = L + ((R - L) >> 1);
    if (arr[mid] <= value) {
      index = mid;
      L = mid + 1;
    } else {
      R = mid - 1;
    }
  }
  return index;
}

# 非必要条件-有序

有序并不是所有问题求解时使用二分的必要条件,只要能够正确构建左右两侧的淘汰逻辑,就可以二分,例如局部最小值问题。

问题:给定一个无序的数组,任意相邻元素不相等,返回一个局部最小元素即可。局部最小值的定义:

  1. a0a_{0}a0​ < a1a_{1}a1​,则a0a_{0}a0​ 局部最小。
  2. an−1a_{n-1}an−1​ > ana_{n}an​,则ana_{n}an​ 局部最小。
  3. ai−1a_{i-1}ai−1​ < aia_{i}ai​ < ai+1a_{i + 1}ai+1​,则aia_{i}ai​ 局部最小。
public static int bsAwesome(int[] arr) {
  if (arr == null || arr.length == 0) {
    return -1; 
  }
  if (arr.length == 1 || arr[0] < arr[1]) {
    return 0;
  }
  if (arr[arr.length - 1] < arr[arr.length - 2]) {
    return arr.length - 1;
  }
  int left = 1;
  int right = arr.length - 2;
  int mid = 0;
  while (left < right) {
    mid = left + ((right - left) >> 1);
    if (arr[mid] > arr[mid - 1]) {
      right = mid - 1;
    } else if (arr[mid] > arr[mid + 1]) {
      left = mid + 1;
    } else {
      return mid;
    }
  }
  return left;
}
#数据结构与算法
上次更新: 5/21/2023, 11:34:33 PM
异或运算

异或运算→

最近更新
01
2025
01-15
02
Elasticsearch面试题
07-17
03
Elasticsearch进阶
07-16
更多文章>
Theme by Vdoing
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式