二分猜答案

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)

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

int ans = suf[0], pre = 0;

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

if (s[i] == '1') {

++pre = min(pre + 2, i + 1);
ans = min(ans, pre + suf[i +
++ 1]);

}

return ans;

}

};

lc286

前后缀分解

class Solution {

public:

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

{

int n=nums.size();

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

f[0]=1;

g[n-1]=1;//init

//空间换时间

//预处理

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

f[i]=f[i-1]*nums[i-1];

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

g[j]=g[j+1]*nums[j+1];

//cal

vector<int> ret(n);

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

++ret[i]=f[i]*g[i];++

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 (arr[i + 1] * 1.0 / arr[j] <= x)

i++;

if (arr[i] * 1.0 / arr[j] <= x) {

ans += i + 1;

if (arr[i] * 1.0 / arr[j] > large) {

a = arr[i];

b = arr[j];

large = arr[i] * 1.0 / arr[j];

}

}

}

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 使得 arr[i]/arr[j] ≤ mid (因为数组有序, i 越大,分数越大);

  • 此时, i+1 就是以 arr[j] 为分母、满足条件的分数个数(分子可以是 arr[0]~arr[i] );

  • 同时记录这些分数中最大的那个(因为统计数==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+=arr[i];

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;

}

};

相关推荐
_OP_CHEN1 天前
【算法基础篇】(四十二)数论之欧拉函数深度精讲:从互质到数论应用
c++·算法·蓝桥杯·数论·欧拉函数·算法竞赛·acm/icpc
Eloudy1 天前
模板函数动态库与头文件设计示例
算法·cuda
星云数灵1 天前
大模型高级工程师考试练习题4
人工智能·算法·机器学习·大模型·大模型考试题库·阿里云aca·阿里云acp大模型考试题库
千金裘换酒1 天前
Leetcode 二叉树中序遍历 前序遍历 后序遍历(递归)
算法·leetcode·职场和发展
姓蔡小朋友1 天前
算法-双指针
算法
D_FW1 天前
数据结构第三章:栈、队列与数组
数据结构·算法
Tisfy1 天前
LeetCode 1339.分裂二叉树的最大乘积:深度优先搜索(一次DFS+存数组并遍历)
算法·leetcode·深度优先·题解
csdn_aspnet1 天前
MATLAB 高效算法实战:数据分析与算法优化的效率秘诀
算法·matlab·数据分析
budingxiaomoli1 天前
优选算法--链表
数据结构·算法·链表