大数据领域分布式计算的混合计算模式
2026/1/15 20:27:58
| 模式 | 特点 | 适用场景 | 关键判断 |
|---|---|---|---|
| 标准二分 | 查找确切存在的值 | 有序数组查找 | nums[mid] == target |
| 寻找边界 | 查找第一个/最后一个位置 | 重复元素、插入位置 | 条件变化时的边界处理 |
| 抽象二分 | 在抽象条件上二分 | 答案有单调性、最优化问题 | 定义判定函数 |
intbinarySearch(vector<int>&nums,inttarget){intleft=0,right=nums.size()-1;while(left<=right){intmid=left+(right-left)/2;// 防止溢出if(nums[mid]==target){returnmid;// 找到目标}elseif(nums[mid]<target){left=mid+1;// 搜索右半部分}else{right=mid-1;// 搜索左半部分}}return-1;// 未找到}// 寻找第一个 >= target 的位置(lower_bound)intfindFirstGreaterOrEqual(vector<int>&nums,inttarget){intleft=0,right=nums.size();// 注意:右开区间while(left<right){intmid=left+(right-left)/2;if(nums[mid]>=target){right=mid;// 保留mid,继续向左找}else{left=mid+1;// 向右找}}returnleft;// 第一个 >= target 的位置}// 如果是这些问题,考虑二分查找:-"在排序数组中查找元素的第一个和最后一个位置"-"寻找旋转排序数组中的最小值"-"在 D 天内送达包裹的能力"(最优化问题)-"制作 m 束花所需的最少天数"-"分割数组的最大值"[left, right]:while(left <= right),更新时mid±1[left, right):while(left < right),更新时left=mid+1或right=mid// 不同问题的判断条件if(nums[mid]==target)// 标准查找if(nums[mid]>=target)// 寻找左边界if(nums[mid]>target)// 寻找右边界if(canFinish(piles,mid,h))// 最优化问题(抽象条件)mid的计算方式:mid = left + (right-left)/2(向下取整)left = mid+1或right = mid-1// 问题:在排序数组中查找目标值intsearch(vector<int>&nums,inttarget){intleft=0,right=nums.size()-1;while(left<=right){intmid=left+(right-left)/2;if(nums[mid]==target)returnmid;elseif(nums[mid]<target)left=mid+1;elseright=mid-1;}return-1;}// 问题:在排序数组中查找元素的第一个和最后一个位置vector<int>searchRange(vector<int>&nums,inttarget){// 找左边界:第一个 >= target 的位置intleft=lower_bound(nums.begin(),nums.end(),target)-nums.begin();// 找右边界:第一个 > target 的位置 - 1intright=upper_bound(nums.begin(),nums.end(),target)-nums.begin()-1;if(left<=right)return{left,right};return{-1,-1};}// 问题:搜索旋转排序数组intsearchRotated(vector<int>&nums,inttarget){intleft=0,right=nums.size()-1;while(left<=right){intmid=left+(right-left)/2;if(nums[mid]==target)returnmid;// 判断哪一部分是有序的if(nums[left]<=nums[mid]){// 左半部分有序if(nums[left]<=target&&target<nums[mid]){right=mid-1;// 目标在有序的左半部分}else{left=mid+1;// 目标在右半部分}}else{// 右半部分有序if(nums[mid]<target&&target<=nums[right]){left=mid+1;// 目标在有序的右半部分}else{right=mid-1;// 目标在左半部分}}}return-1;}// 问题:在 D 天内送达包裹的能力intshipWithinDays(vector<int>&weights,intdays){// 确定二分搜索边界intleft=*max_element(weights.begin(),weights.end());// 最小能力intright=accumulate(weights.begin(),weights.end(),0);// 最大能力while(left<right){intmid=left+(right-left)/2;if(canShip(weights,days,mid)){right=mid;// 尝试更小的能力}else{left=mid+1;// 需要更大的能力}}returnleft;}boolcanShip(vector<int>&weights,intdays,intcapacity){intcurrent=0,needed=1;for(intweight:weights){if(current+weight>capacity){needed++;current=0;}current+=weight;}returnneeded<=days;}从理解原理开始
二分查找为什么是 O(log n)? 每次比较排除一半元素 → 最多 log₂n 次掌握两种模板
手动模拟过程
数组:[1,3,5,7,9,11]查找:7步骤1:left=0,right=5,mid=2,nums[2]=5<7→ left=3步骤2:left=3,right=5,mid=4,nums[4]=9>7→ right=3步骤3:left=3,right=3,mid=3,nums[3]=7==7→ 找到注意常见陷阱
mid = left + (right-left)/2从"找答案"到"猜答案+验证"
传统:直接找到正确答案 二分:猜一个答案 → 验证是否正确 → 调整猜测判定函数的编写
// 最优化问题的关键:编写判定函数boolisValid(intguess){// 判断 guess 是否满足条件// 通常需要 O(n) 或 O(m) 的验证}Level 1: 基础二分查找(704题) Level 2: 寻找边界(34题) Level 3: 旋转数组搜索(33、81题) Level 4: 抽象二分查找(875、1011题) Level 5: 二维二分查找(74、240题) Level 6: 复杂最优化问题(410、1231题)lower_bound和upper_bound的运用二分查找 = 有序数据 + 折半排除 + 边界处理
// 在循环中添加打印,观察搜索过程while(left<=right){intmid=left+(right-left)/2;cout<<"left="<<left<<", right="<<right<<", mid="<<mid<<", nums[mid]="<<nums[mid]<<endl;// ...}掌握二分查找的关键在于理解其"减而治之"的思想,并通过大量练习熟悉各种变体。从标准二分开始,逐步挑战更复杂的问题,最终能够灵活运用二分思想解决各类最优化问题。