今日分享 整数二分

  1. 二分法的核心思想

二分法就像猜数字游戏。每次猜中间数,根据大小提示排除一半答案。

这种方法将 O(n) 的线性查找,优化到 O(log n) 的对数级别。

  1. 整数二分的"奥义"

整数二分的精髓在于边界处理。因为整数没有"中点",必须明确:

查找区间是 [left, right] (闭区间)

每次排除时,边界如何更新才不会漏掉答案

处理不好边界,就会导致死循环或漏掉正确答案。

  1. 两种经典模板与技巧

根据要找的目标不同,分为两种模板:

模板一:查找第一个满足条件的值

用于查找"左边界",例如:数组中第一个大于等于 x 的数。

int findFirst(int *nums, int n, int x) {

int left = 0, right = n - 1;

int ans = n; // 初始化为一个不可能的位置

while (left <= right) {

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

if (nums[mid] >= x) { // 满足条件,尝试找更左边的

ans = mid;

right = mid - 1;

} else { // 不满足,去右边找

left = mid + 1;

}

}

return ans;

}

模板二:查找最后一个满足条件的值

用于查找"右边界",例如:数组中最后一个小于等于 x 的数。

int findLast(int *nums, int n, int x) {

int left = 0, right = n - 1;

int ans = -1; // 初始化为一个不可能的位置

while (left <= right) {

int mid = left + (right - left) / 2;

if (nums[mid] <= x) { // 满足条件,尝试找更右边的

ans = mid;

left = mid + 1;

} else { // 不满足,去左边找

right = mid - 1;

}

}

return ans;

}

  1. 解题技巧总结

  2. 确定区间:永远使用闭区间 [left, right] ,逻辑最清晰。

  3. 循环条件:使用 left <= right ,保证退出时所有元素都被检查。

  4. 计算中点:用 mid = left + (right - left) / 2 避免 left + right 溢出。

  5. 边界移动:根据"找左边界"还是"找右边界"选择移动 left 或 right 。

  6. 验证答案:退出循环后,记得检查 ans 是否在合理范围内。

例题实战:在排序数组中查找元素的第一个和最后一个位置

题目描述:

给定一个按照升序排列的整数数组 nums ,和一个目标值 target 。找出给定目标值在数组中的开始位置和结束位置。如果数组中不存在目标值,返回 [-1, -1] 。

示例:

输入: nums = [5,7,7,8,8,10] , target = 8

输出: [3, 4]

C 语言实现

#include <stdio.h>

#include <stdlib.h>

int* searchRange(int* nums, int numsSize, int target, int* returnSize) {

*returnSize = 2;

int* result = (int*)malloc(sizeof(int) * 2);

result[0] = -1;

result[1] = -1;

// 找左边界

int left = 0, right = numsSize - 1;

while (left <= right) {

int mid = left + (right - left) / 2;

if (nums[mid] >= target) {

right = mid - 1;

} else {

left = mid + 1;

}

}

if (left < numsSize && nums[left] == target) {

result[0] = left;

} else {

return result;

}

// 找右边界

left = 0;

right = numsSize - 1;

while (left <= right) {

int mid = left + (right - left) / 2;

if (nums[mid] <= target) {

left = mid + 1;

} else {

right = mid - 1;

}

}

result[1] = right;

return result;

}

int main() {

int nums[] = {5,7,7,8,8,10};

int target = 8;

int returnSize;

int* result = searchRange(nums, 6, target, &returnSize);

printf("[%d, %d]\n", result[0], result[1]);

free(result);

return 0;

}

C++ 实现

#include <iostream>

#include <vector>

using namespace std;

vector<int> searchRange(vector<int>& nums, int target) {

vector<int> result(2, -1);

int n = nums.size();

if (n == 0) return result;

// 找左边界

int left = 0, right = n - 1;

while (left <= right) {

int mid = left + (right - left) / 2;

if (nums[mid] >= target) {

right = mid - 1;

} else {

left = mid + 1;

}

}

if (left < n && nums[left] == target) {

result[0] = left;

} else {

return result;

}

// 找右边界

left = 0;

right = n - 1;

while (left <= right) {

int mid = left + (right - left) / 2;

if (nums[mid] <= target) {

left = mid + 1;

} else {

right = mid - 1;

}

}

result[1] = right;

return result;

}

int main() {

vector<int> nums = {5,7,7,8,8,10};

int target = 8;

vector<int> res = searchRange(nums, target);

cout << "[" << res[0] << ", " << res[1] << "]" << endl;

return 0;

}

Python 实现

def searchRange(nums, target):

result = [-1, -1]

n = len(nums)

if n == 0:

return result

找左边界

left, right = 0, n - 1

while left <= right:

mid = left + (right - left) // 2

if nums[mid] >= target:

right = mid - 1

else:

left = mid + 1

if left < n and nums[left] == target:

result[0] = left

else:

return result

找右边界

left, right = 0, n - 1

while left <= right:

mid = left + (right - left) // 2

if nums[mid] <= target:

left = mid + 1

else:

right = mid - 1

result[1] = right

return result

nums = [5,7,7,8,8,10]

target = 8

print(searchRange(nums, target))

Java 实现

import java.util.Arrays;

public class SearchRange {

public static int[] searchRange(int[] nums, int target) {

int[] result = {-1, -1};

int n = nums.length;

if (n == 0) return result;

// 找左边界

int left = 0, right = n - 1;

while (left <= right) {

int mid = left + (right - left) / 2;

if (nums[mid] >= target) {

right = mid - 1;

} else {

left = mid + 1;

}

}

if (left < n && nums[left] == target) {

result[0] = left;

} else {

return result;

}

// 找右边界

left = 0;

right = n - 1;

while (left <= right) {

int mid = left + (right - left) / 2;

if (nums[mid] <= target) {

left = mid + 1;

} else {

right = mid - 1;

}

}

result[1] = right;

return result;

}

public static void main(String[] args) {

int[] nums = {5,7,7,8,8,10};

int target = 8;

int[] res = searchRange(nums, target);

System.out.println(Arrays.toString(res));

}

}

相关推荐
jikiecui1 分钟前
信奥崔老师:实数型: float、double
c++·算法
知花实央l21 分钟前
【数字逻辑】数字逻辑实验实战:74HC151实现逻辑函数+74HC138搭全加器(附接线步骤+避坑指南)
算法·容器·测试用例·逻辑回归
CoovallyAIHub23 分钟前
突破性开源模型DepthLM问世:视觉语言模型首次实现精准三维空间理解
深度学习·算法·计算机视觉
WaWaJie_Ngen40 分钟前
【OpenGL】模板测试(StencilTest)
c++·算法·游戏·游戏引擎·游戏程序·图形渲染
Yuroo zhou1 小时前
破空驭风,智领未来 --5KG物流配送无人机展示飞行!
人工智能·算法·机器人·硬件工程·无人机
CoovallyAIHub1 小时前
ICCV 2025 最佳论文出炉:CMU 团队用「AI 积木大师」BrickGPT 摘得桂冠!
深度学习·算法·计算机视觉
喜欢吃燃面1 小时前
算法中的链表结构
开发语言·c++·学习·算法
Juan_20121 小时前
P1041题解
c++·算法·题解·搜索
晨非辰2 小时前
【数据结构入坑指南】--《层序分明:堆的实现、排序与TOP-K问题一站式攻克(源码实战)》
c语言·开发语言·数据结构·算法·面试
hansang_IR2 小时前
【题解】P2217 [HAOI2007] 分割矩阵 [记忆化搜索]
c++·数学·算法·记忆化搜索·深搜