二分猜答案

lc2167

前后缀分解 -> 线性dp

前缀数组记录从左侧处理违禁车厢的最小时间、后缀数组记录从右侧处理的最小时间

遍历每个位置时合并两侧时间,取最小值得到移除所有违禁车厢的最少时间

class Solution {

public:

int minimumTime(string s) {

int n = s.length();

vector<int> suf(n + 1);

for (int i = n - 1; i >= 0; --i)

sufi = si == '0' ? sufi + 1 : ++min(sufi + 1 + 2, n - i); //suf预处理 记录选择++

int ans = suf0, pre = 0;

for (int i = 0; i < n; ++i)

if (si == '1') {

++***pre = min(pre + 2, i + 1);
ans = min(ans, pre + sufi +***++ 1);

}

return ans;

}

};

lc286

前后缀分解

class Solution {

public:

vector<int> productExceptSelf(vector<int>& nums)

{

int n=nums.size();

vector<int> f(n),g(n);

f0=1;

gn-1=1;//init

//空间换时间

//预处理

for(int i=1;i<=n-1;i++)

fi=fi-1*numsi-1;

for(int j=n-2;j>=0;j--)

gj=gj+1*numsj+1;

//cal

vector<int> ret(n);

for(int i=0;i<n;i++)

++reti=fi*gi;++

return ret;

}

};

lc786

二分查找分数值范围,统计小于等于中间值的分数个数,定位第k小的素数分数并返回

#include <vector>

using namespace std;

class Solution {

private:

vector<int> arr;

int n, a, b;

public:

vector<int> kthSmallestPrimeFraction(vector<int>& _arr, int k) {

arr = _arr;

n = arr.size();

double l = 0, r = 1;

while (true) {

double mid = (l + r) / 2;

int cnt = check(mid);

if (cnt > k) r = mid;

else if (cnt < k) l = mid;

else break;

}

return {a, b};

}

private:

int check(double x) {

int ans = 0;

double large = 0;

for (int i = 0, j = 1; j < n; j++) {

while (arri + 1 * 1.0 / arrj <= x)

i++;

if (arri * 1.0 / arrj <= x) {

ans += i + 1;

if (arri * 1.0 / arrj > large) {

a = arri;

b = arrj;

large = arri * 1.0 / arrj;

}

}

}

return ans;

}

};

核心逻辑:用二分查找定位"第k小的素数分数",不用暴力枚举所有分数,效率更高

  1. 前提:输入数组是从小到大排序的素数,要找的是"两个素数相除(分子在前、分母在后,分子<分母)"中第k小的那个分数(比如数组2,3,5,分数有2/3、2/5、3/5,第2小是2/5)

  2. 二分查找的是什么?

不直接找分数,而是找"分数的数值大小"。因为所有可能的分数都在 0~1 之间(分子<分母),所以在 0,1 区间里二分:

  • 每次取中间值 mid ,++统计"所有小于等于 mid 的分数有多少个"(用 check 函数算)++。

  • 如果统计数 >k:说明第k小的分数比 mid 小,缩小右边界;

  • 如果统计数 <k:说明第k小的分数比 mid 大,扩大左边界;

  • 统计数 ==k:说明 mid 刚好"卡"在第k小的分数上,找到目标。

  1. check函数怎么统计?

用"双指针"高效计数(不用两两枚举,避免超时):

  • 固定分母 j ,找最大的分子 i 使得 arri/arrj ≤ mid (因为数组有序, i 越大,分数越大);

  • 此时, i+1 就是以 arrj 为分母、满足条件的分数个数(分子可以是 arr0~arri );

  • 同时记录这些分数中最大的那个(因为统计数==k时,这个最大分数就是第k小的目标)

lc1300

对数组排序后,通过二分查找确定"将数组中大于该值的元素替换为该值后总和最接近目标值"的数,用二分+迭代器定位_计算总和

using namespace std;

class Solution

{

public:

int findBestValue(vector<int>& arr, int target)

{

sort(arr.begin(),arr.end());

int l=0, r=arr.back();

int n=arr.size();

auto check=\&(int x)->int

{

int ret=0;

auto it=lower_bound(arr.begin(),arr.end(),x);

int idx=it-arr.begin();

for(int i=0;i<idx;i++)

ret+=arri;

return ret+(n-idx)*x;

};

while(l<=r)

{

int m=l+(r-l)/2;

if(check(m)<target)

l=m+1;

else

r=m-1;

}

int sum1=check(l), sum2=check(l-1);

return abs(sum1-target) < abs(sum2-target) ? l : l-1;

}

};

相关推荐
BothSavage15 小时前
Trae远程开发中DeepSeek自定义模型4054错误的排查与修复
算法
小林ixn15 小时前
从暴力到KMP:一道题彻底搞懂字符串匹配的前世今生
算法
烬羽17 小时前
字符串算法入门:从反转字符串到回文判断,面试不再慌
算法·面试
先吃饱再说1 天前
判断回文字符串,从一行代码到双指针优化
算法
黄敬峰1 天前
深入理解算法核心:从递归思想、数组扁平化到快速排序
算法
得物技术2 天前
从狂野代码到按目标生产:得物推荐 AI Harness 的工程化实践|AICon 演讲整理
人工智能·算法·架构
AI小老六2 天前
SkillOpt 架构拆解:把 Skill 文本当参数,用执行轨迹训练 Agent
后端·算法·ai编程
胡萝卜术2 天前
从“分数打架”到“排名投票”:为什么你的ChatBI必须用RRF?
算法·设计模式·面试