📢 重要功能通知
为了提供更好的用户体验,我们正在逐步调整网站的整体风格和界面设计。同时需要告知您以下情况:
- 部分页面样式可能会发生变化
- 某些功能的视觉效果可能暂时不一致
- PDF打印功能目前无法使用
- 我们会尽量保持其他功能的正常使用
感谢您的理解与支持!如有任何问题请及时反馈。
📅 公告有效期:即日起至相关功能修复完成
🔄 回退说明:如遇严重问题可联系管理员临时回退
朋友心里想了1-100之间的数字,让你猜:
核心思想:利用数组的有序性,每次比较中间元素,排除一半的搜索空间。
三种情况:
为什么是O(log n)?
具体例子:
| 数组大小 | 最多比较次数 | 线性查找 |
|---|---|---|
| 10 | 4 | 10 |
| 100 | 7 | 100 |
| 1,000 | 10 | 1,000 |
| 1,000,000 | 20 | 1,000,000 |
等待开始查找...
def binary_search(arr, target):
"""
标准二分查找
Args:
arr: 有序数组
target: 查找目标
Returns:
目标元素的索引,如果不存在返回-1
"""
left, right = 0, len(arr) - 1
while left <= right:
# 防止溢出的写法
mid = left + (right - left) // 2
if arr[mid] == target:
return mid # 找到目标
elif arr[mid] < target:
left = mid + 1 # 目标在右半部分
else:
right = mid - 1 # 目标在左半部分
return -1 # 未找到
def binary_search_recursive(arr, target, left=0, right=None):
"""
递归版本的二分查找
"""
if right is None:
right = len(arr) - 1
if left > right:
return -1
mid = left + (right - left) // 2
if arr[mid] == target:
return mid
elif arr[mid] < target:
return binary_search_recursive(arr, target, mid + 1, right)
else:
return binary_search_recursive(arr, target, left, mid - 1)
def binary_search_first(arr, target):
"""
查找第一个等于target的元素
用于处理有重复元素的情况
"""
left, right = 0, len(arr) - 1
result = -1
while left <= right:
mid = left + (right - left) // 2
if arr[mid] == target:
result = mid
right = mid - 1 # 继续在左边查找
elif arr[mid] < target:
left = mid + 1
else:
right = mid - 1
return result
def binary_search_last(arr, target):
"""
查找最后一个等于target的元素
"""
left, right = 0, len(arr) - 1
result = -1
while left <= right:
mid = left + (right - left) // 2
if arr[mid] == target:
result = mid
left = mid + 1 # 继续在右边查找
elif arr[mid] < target:
left = mid + 1
else:
right = mid - 1
return result
def binary_search_insert_position(arr, target):
"""
查找插入位置
返回target应该插入的位置,保持数组有序
"""
left, right = 0, len(arr)
while left < right:
mid = left + (right - left) // 2
if arr[mid] < target:
left = mid + 1
else:
right = mid
return left
def binary_search_range(arr, target):
"""
查找目标元素的范围 [first, last]
"""
first = binary_search_first(arr, target)
if first == -1:
return [-1, -1]
last = binary_search_last(arr, target)
return [first, last]
def binary_search_rotated(arr, target):
"""
在旋转排序数组中查找
例如:[4,5,6,7,0,1,2]
"""
left, right = 0, len(arr) - 1
while left <= right:
mid = left + (right - left) // 2
if arr[mid] == target:
return mid
# 判断哪一半是有序的
if arr[left] <= arr[mid]: # 左半部分有序
if arr[left] <= target < arr[mid]:
right = mid - 1
else:
left = mid + 1
else: # 右半部分有序
if arr[mid] < target <= arr[right]:
left = mid + 1
else:
right = mid - 1
return -1
def binary_search_peak(arr):
"""
寻找峰值元素
峰值:大于左右相邻元素的元素
"""
left, right = 0, len(arr) - 1
while left < right:
mid = left + (right - left) // 2
if arr[mid] < arr[mid + 1]:
left = mid + 1 # 峰值在右边
else:
right = mid # 峰值在左边或就是mid
return left
def binary_search_2d_matrix(matrix, target):
"""
在二维矩阵中查找
矩阵每行递增,每行的第一个元素大于上一行的最后一个元素
"""
if not matrix or not matrix[0]:
return False
m, n = len(matrix), len(matrix[0])
left, right = 0, m * n - 1
while left <= right:
mid = left + (right - left) // 2
# 将一维索引转换为二维坐标
row, col = mid // n, mid % n
if matrix[row][col] == target:
return True
elif matrix[row][col] < target:
left = mid + 1
else:
right = mid - 1
return False
# 测试示例
if __name__ == "__main__":
# 基础测试
arr = [1, 3, 5, 7, 9, 11, 13, 15, 17, 19]
print("数组:", arr)
# 标准二分查找
target = 7
result = binary_search(arr, target)
print(f"查找 {target}: 索引 = {result}")
# 递归版本
result = binary_search_recursive(arr, target)
print(f"递归查找 {target}: 索引 = {result}")
# 有重复元素的情况
arr_dup = [1, 2, 2, 2, 3, 4, 4, 5]
print(f"\n有重复元素的数组: {arr_dup}")
print(f"第一个2的位置: {binary_search_first(arr_dup, 2)}")
print(f"最后一个2的位置: {binary_search_last(arr_dup, 2)}")
print(f"2的范围: {binary_search_range(arr_dup, 2)}")
# 插入位置
print(f"\n插入3.5的位置: {binary_search_insert_position(arr, 8)}")
# 旋转数组
rotated = [4, 5, 6, 7, 0, 1, 2]
print(f"\n旋转数组: {rotated}")
print(f"查找0: {binary_search_rotated(rotated, 0)}")
# 寻找峰值
peak_arr = [1, 2, 3, 1]
print(f"\n数组 {peak_arr} 的峰值索引: {binary_search_peak(peak_arr)}")
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
// 标准二分查找
int binarySearch(vector<int>& arr, int target) {
int left = 0, right = arr.size() - 1;
while (left <= right) {
int mid = left + (right - left) / 2; // 防止溢出
if (arr[mid] == target) {
return mid; // 找到目标
} else if (arr[mid] < target) {
left = mid + 1; // 目标在右半部分
} else {
right = mid - 1; // 目标在左半部分
}
}
return -1; // 未找到
}
// 递归版本
int binarySearchRecursive(vector<int>& arr, int target, int left, int right) {
if (left > right) {
return -1;
}
int mid = left + (right - left) / 2;
if (arr[mid] == target) {
return mid;
} else if (arr[mid] < target) {
return binarySearchRecursive(arr, target, mid + 1, right);
} else {
return binarySearchRecursive(arr, target, left, mid - 1);
}
}
// 查找第一个等于target的元素
int binarySearchFirst(vector<int>& arr, int target) {
int left = 0, right = arr.size() - 1;
int result = -1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (arr[mid] == target) {
result = mid;
right = mid - 1; // 继续在左边查找
} else if (arr[mid] < target) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return result;
}
// 查找最后一个等于target的元素
int binarySearchLast(vector<int>& arr, int target) {
int left = 0, right = arr.size() - 1;
int result = -1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (arr[mid] == target) {
result = mid;
left = mid + 1; // 继续在右边查找
} else if (arr[mid] < target) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return result;
}
// 查找插入位置
int searchInsertPosition(vector<int>& arr, int target) {
int left = 0, right = arr.size();
while (left < right) {
int mid = left + (right - left) / 2;
if (arr[mid] < target) {
left = mid + 1;
} else {
right = mid;
}
}
return left;
}
// 查找元素范围
vector<int> searchRange(vector<int>& arr, int target) {
int first = binarySearchFirst(arr, target);
if (first == -1) {
return {-1, -1};
}
int last = binarySearchLast(arr, target);
return {first, last};
}
// 在旋转排序数组中查找
int searchRotated(vector<int>& arr, int target) {
int left = 0, right = arr.size() - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (arr[mid] == target) {
return mid;
}
// 判断哪一半是有序的
if (arr[left] <= arr[mid]) { // 左半部分有序
if (arr[left] <= target && target < arr[mid]) {
right = mid - 1;
} else {
left = mid + 1;
}
} else { // 右半部分有序
if (arr[mid] < target && target <= arr[right]) {
left = mid + 1;
} else {
right = mid - 1;
}
}
}
return -1;
}
// 寻找峰值
int findPeakElement(vector<int>& arr) {
int left = 0, right = arr.size() - 1;
while (left < right) {
int mid = left + (right - left) / 2;
if (arr[mid] < arr[mid + 1]) {
left = mid + 1; // 峰值在右边
} else {
right = mid; // 峰值在左边或就是mid
}
}
return left;
}
// 二分查找模板类(支持自定义比较)
template<typename T>
class BinarySearcher {
public:
// 标准二分查找
static int search(const vector<T>& arr, const T& target) {
int left = 0, right = arr.size() - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (arr[mid] == target) {
return mid;
} else if (arr[mid] < target) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return -1;
}
// 使用自定义比较函数
template<typename Compare>
static int searchWithCompare(const vector<T>& arr, const T& target, Compare comp) {
int left = 0, right = arr.size() - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (!comp(arr[mid], target) && !comp(target, arr[mid])) {
return mid; // 相等
} else if (comp(arr[mid], target)) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return -1;
}
};
// 打印数组
void printArray(const vector<int>& arr) {
for (int x : arr) {
cout << x << " ";
}
cout << endl;
}
int main() {
// 基础测试
vector<int> arr = {1, 3, 5, 7, 9, 11, 13, 15, 17, 19};
cout << "数组: ";
printArray(arr);
// 标准二分查找
int target = 7;
int result = binarySearch(arr, target);
cout << "查找 " << target << ": 索引 = " << result << endl;
// 递归版本
result = binarySearchRecursive(arr, target, 0, arr.size() - 1);
cout << "递归查找 " << target << ": 索引 = " << result << endl;
// 有重复元素
vector<int> arrDup = {1, 2, 2, 2, 3, 4, 4, 5};
cout << "\n有重复元素的数组: ";
printArray(arrDup);
cout << "第一个2的位置: " << binarySearchFirst(arrDup, 2) << endl;
cout << "最后一个2的位置: " << binarySearchLast(arrDup, 2) << endl;
auto range = searchRange(arrDup, 2);
cout << "2的范围: [" << range[0] << ", " << range[1] << "]" << endl;
// 插入位置
cout << "\n在原数组中插入8的位置: " << searchInsertPosition(arr, 8) << endl;
// 旋转数组
vector<int> rotated = {4, 5, 6, 7, 0, 1, 2};
cout << "\n旋转数组: ";
printArray(rotated);
cout << "查找0: " << searchRotated(rotated, 0) << endl;
// 寻找峰值
vector<int> peakArr = {1, 2, 3, 1};
cout << "\n数组 ";
printArray(peakArr);
cout << "峰值索引: " << findPeakElement(peakArr) << endl;
// 使用模板类
cout << "\n使用模板类查找: " << BinarySearcher<int>::search(arr, 13) << endl;
return 0;
}
import java.util.*;
public class BinarySearch {
// 标准二分查找
public static int binarySearch(int[] arr, int target) {
int left = 0, right = arr.length - 1;
while (left <= right) {
int mid = left + (right - left) / 2; // 防止溢出
if (arr[mid] == target) {
return mid; // 找到目标
} else if (arr[mid] < target) {
left = mid + 1; // 目标在右半部分
} else {
right = mid - 1; // 目标在左半部分
}
}
return -1; // 未找到
}
// 递归版本
public static int binarySearchRecursive(int[] arr, int target, int left, int right) {
if (left > right) {
return -1;
}
int mid = left + (right - left) / 2;
if (arr[mid] == target) {
return mid;
} else if (arr[mid] < target) {
return binarySearchRecursive(arr, target, mid + 1, right);
} else {
return binarySearchRecursive(arr, target, left, mid - 1);
}
}
// 查找第一个等于target的元素
public static int binarySearchFirst(int[] arr, int target) {
int left = 0, right = arr.length - 1;
int result = -1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (arr[mid] == target) {
result = mid;
right = mid - 1; // 继续在左边查找
} else if (arr[mid] < target) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return result;
}
// 查找最后一个等于target的元素
public static int binarySearchLast(int[] arr, int target) {
int left = 0, right = arr.length - 1;
int result = -1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (arr[mid] == target) {
result = mid;
left = mid + 1; // 继续在右边查找
} else if (arr[mid] < target) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return result;
}
// 查找插入位置
public static int searchInsertPosition(int[] arr, int target) {
int left = 0, right = arr.length;
while (left < right) {
int mid = left + (right - left) / 2;
if (arr[mid] < target) {
left = mid + 1;
} else {
right = mid;
}
}
return left;
}
// 查找元素范围
public static int[] searchRange(int[] arr, int target) {
int first = binarySearchFirst(arr, target);
if (first == -1) {
return new int[]{-1, -1};
}
int last = binarySearchLast(arr, target);
return new int[]{first, last};
}
// 在旋转排序数组中查找
public static int searchRotated(int[] arr, int target) {
int left = 0, right = arr.length - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (arr[mid] == target) {
return mid;
}
// 判断哪一半是有序的
if (arr[left] <= arr[mid]) { // 左半部分有序
if (arr[left] <= target && target < arr[mid]) {
right = mid - 1;
} else {
left = mid + 1;
}
} else { // 右半部分有序
if (arr[mid] < target && target <= arr[right]) {
left = mid + 1;
} else {
right = mid - 1;
}
}
}
return -1;
}
// 寻找峰值
public static int findPeakElement(int[] arr) {
int left = 0, right = arr.length - 1;
while (left < right) {
int mid = left + (right - left) / 2;
if (arr[mid] < arr[mid + 1]) {
left = mid + 1; // 峰值在右边
} else {
right = mid; // 峰值在左边或就是mid
}
}
return left;
}
// 二分查找的泛型实现
public static <T extends Comparable<T>> int binarySearchGeneric(T[] arr, T target) {
int left = 0, right = arr.length - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
int cmp = arr[mid].compareTo(target);
if (cmp == 0) {
return mid;
} else if (cmp < 0) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return -1;
}
// 打印数组
public static void printArray(int[] arr) {
System.out.println(Arrays.toString(arr));
}
public static void main(String[] args) {
// 基础测试
int[] arr = {1, 3, 5, 7, 9, 11, 13, 15, 17, 19};
System.out.print("数组: ");
printArray(arr);
// 标准二分查找
int target = 7;
int result = binarySearch(arr, target);
System.out.println("查找 " + target + ": 索引 = " + result);
// 递归版本
result = binarySearchRecursive(arr, target, 0, arr.length - 1);
System.out.println("递归查找 " + target + ": 索引 = " + result);
// 有重复元素
int[] arrDup = {1, 2, 2, 2, 3, 4, 4, 5};
System.out.print("\n有重复元素的数组: ");
printArray(arrDup);
System.out.println("第一个2的位置: " + binarySearchFirst(arrDup, 2));
System.out.println("最后一个2的位置: " + binarySearchLast(arrDup, 2));
int[] range = searchRange(arrDup, 2);
System.out.println("2的范围: " + Arrays.toString(range));
// 插入位置
System.out.println("\n在原数组中插入8的位置: " + searchInsertPosition(arr, 8));
// 旋转数组
int[] rotated = {4, 5, 6, 7, 0, 1, 2};
System.out.print("\n旋转数组: ");
printArray(rotated);
System.out.println("查找0: " + searchRotated(rotated, 0));
// 寻找峰值
int[] peakArr = {1, 2, 3, 1};
System.out.print("\n数组 ");
printArray(peakArr);
System.out.println("峰值索引: " + findPeakElement(peakArr));
// 使用泛型
Integer[] integerArr = {1, 3, 5, 7, 9};
System.out.println("\n泛型查找5: " + binarySearchGeneric(integerArr, 5));
// 使用Java内置的二分查找
System.out.println("\nJava Arrays.binarySearch: " +
Arrays.binarySearch(arr, 13));
}
}
电子词典、数据库索引等使用二分查找快速定位
在排行榜中快速查找玩家排名,碰撞检测优化
在已排序的文件列表中快速查找文件
求平方根、方程求解等数值方法
在时间序列数据中查找特定时间点的数据
在传感器数据中快速定位异常值
1. 数组必须有序
2. 支持随机访问(数组结构)
额外考虑:
while (left <= right):
while (left < right):
示例对比:
// 标准查找
while (left <= right) {
mid = left + (right - left) / 2;
if (arr[mid] == target) return mid;
else if (arr[mid] < target) left = mid + 1;
else right = mid - 1;
}
// 查找左边界
while (left < right) {
mid = left + (right - left) / 2;
if (arr[mid] < target) left = mid + 1;
else right = mid;
}
问题分析:
解决方案:
mid = left + (right - left) / 2(推荐)mid = left + ((right - left) >> 1)(位运算版本)mid = (left + right) >>> 1(Java无符号右移)其他语言的处理:
问题描述:
数组原本有序,被旋转了若干位。如:[4,5,6,7,0,1,2]
解题思路:
代码实现:
def findMin(arr):
left, right = 0, len(arr) - 1
while left < right:
mid = left + (right - left) // 2
if arr[mid] > arr[right]:
left = mid + 1 # 最小值在右边
elif arr[mid] < arr[right]:
right = mid # 最小值在左边或就是mid
else:
right -= 1 # 处理重复元素
return arr[left]
时间复杂度:O(log n),有重复时最坏O(n)