6. 在排序数组中查找元素的第一个和最后一个位置
class Solution {
public:
vector<int> searchRange(vector<int>& nums, int target) {
return {find(nums,target,true),find(nums,target,false)};
}
int find(vector<int>& nums, int target, bool minType) {
int left = 0, right = nums.size() - 1;
int ans = -1;//默认为-1
while (left <= right) {//当搜索区间位于两指针之间
int mid = left + (right - left) / 2;//二分查找
if (nums[mid] == target) {
ans = mid;
if (minType) right = mid - 1;//找左边界(注意没写反)
else left = mid + 1;}//找右边界(注意没写反)
else if (target < nums[mid]) right = mid - 1;//移动右指针到二分位置
else left = mid + 1;//左指针移到二分位置
}
return ans;
}
};
8. 找出第k小的数对距离
class Solution {
public:
int smallestDistancePair(vector<int>& nums, int k) {
sort(nums.begin(), nums.end());//排序
int n = nums.size();
int left = 0, right = nums.back() - nums.front();
while (left <= right) {
int mid = (left + right) / 2;
int cnt = 0;//计算所有距离小于等于mid的数对数目cnt
for (int j = 0; j < n; j++) {
int i = lower_bound(nums.begin(), nums.begin() + j, nums[j] - mid) - nums.begin();
cnt += j - i;
}
if (cnt >= k) right = mid - 1;
else left = mid + 1;
}
return left;
}
};
9. 爱吃香蕉的珂珂
class Solution {
public:
int minEatingSpeed(vector<int>& piles, int h) {
long sum =0;int max_ = 0;
for(int x:piles){
sum+=x;
max_ = max(max_,x);}
int min_ = ceil(sum*1.0/h);//向上取整
while(min_<max_){
int times = 0;
int mid = (max_+min_)/2;
for(int x:piles)
times = times + ceil(x*1.0/mid);
if(times==h) max_ = mid; //找左边界动右边
else if(times<h) max_ = mid;
else if(times>h) min_ = mid+1;//找左边界
}
return min_;
}
};
10. 使结果不超过阈值的最小除数
class Solution {
public:
int smallestDivisor(vector<int>& nums, int threshold) {
int min_ = 1; int max_ = *max_element(nums.begin(), nums.end());
while(min_<max_){//使得尽可能小,取左边界
int sum = 0;
int mid = (min_+max_)/2;
for(int &x:nums)
sum+=ceil(x*1.0/mid);
if(sum>threshold) min_ = mid + 1;//如果相等,也要使得尽可能除数变小,所以是降上界
else max_ = mid;
}
return min_;
}
};
11. 完成旅途的最少时间
class Solution {
public:
long long minimumTime(vector<int>& time, int totalTrips) {
long long min_ = 1; long long max_ = *min_element(time.begin(), time.end());
max_ = max_ * totalTrips;
while(min_<max_){
long long sum = 0;
long long mid = (min_+max_)/2;//当前总时间
for(int &x:time)
sum+=mid/x;;//每个车能进行的趟数求和
if(sum>=totalTrips) max_ = mid;//要使得时间尽可能小,相等也要降
else min_ = mid + 1;
}
return min_;
}
};
12. 每个小孩最多能分到多少糖果
class Solution {
public:
int maximumCandies(vector<int>& candies, long long k) {
if(accumulate(candies.begin(),candies.end(),0ll)<k) return 0;
long long min_ = 1; long long max_ = *max_element(candies.begin(), candies.end());
while(min_<max_){
long long sum = 0;
long long mid = (min_+max_+1)/2;//每个孩子所拿糖果数,这里需要往上取
//不加1,直接整除,默认是往下取
for(int &x:candies)
sum+=x/mid;;//可以分成多少满足条件的堆
if(sum>=k) min_ = mid;//满足条件的情况下,
//下一次糖果数往上取,但在该次要保证min_值始终满足条件,用于可能的输出
else max_ = mid-1;
}
return min_;
}
};
13. 准时到达的列车最小时速
class Solution {
public:
int minSpeedOnTime(vector<int>& dist, double hour) {
if(dist.size()-1>=hour) return -1;
int min_ = 1; int max_ = INT_MAX-1;
while(min_<max_){
int mid = (max_+min_)/2;//最小化时速
double sum = 0;
for(int i=0;i<dist.size()-1;i++)
sum+=ceil(dist[i]*1.0/mid);//当前用时和
sum+=dist.back()*1.0/mid;
if(sum<=hour) max_ = mid; //满足条件,找下界
else min_ = mid+1;
}
return min_;
}
};
14. 在 D 天内送达包裹的能力
class Solution {
public:
int shipWithinDays(vector<int>& weights, int days) {
int left = *max_element(weights.begin(), weights.end());
int right = accumulate(weights.begin(),weights.end(),0);
while(left<right){
int mid = left + (right-left)/2;
int cur = 1;//所用天数
int ws = 0;//当前累积载重
for(int i=0;i<weights.size();i++){
if(ws+weights[i]>mid){
ws = 0;//清零换一天
cur++;
}
ws+=weights[i];
}
//
if(cur<=days) right = mid;//缩小到下边界
else left = mid + 1;
}
return right;
}
};
15. 分配给商店的最多商品的最小值
class Solution {
public:
int minimizedMaximum(int n, vector<int>& quantities) {
int left = 1; int right = *max_element(quantities.begin(),quantities.end());
while(left<right){
int sum = 0;//可以分配给商店的最小数量
int mid = (left+right)/2;//当前分配的最多商品数
for(int &x:quantities)
sum+=ceil(x*1.0/mid);//下面需要最小化mid,即相等时也要使其减少,找到下界
if(sum>n) left = mid+1;
else right = mid;
}
return left;
}
};
16. 袋子里最少数目的球
class Solution {
public:
int minimumSize(vector<int>& nums, int maxOperations) {
int left = 1;
int right = *max_element(nums.begin(),nums.end());//最大开销是最大值
while(left<right){
long sum = 0;//需要的次数
int mid = (left+right)/2;//全部处理到当前规模
for(int &x:nums)//找规律得到处理次数
sum+=ceil(x*1.0/mid)-1;
if(sum>maxOperations) left = mid + 1;//这里要最小化该mid值,即满足条件也要取下界
else right = mid;
}
return right;
}
};
17. 制作 m 束花所需的最少天数
二分法+贪心获取最多相邻块数
class Solution {
public:
int minDays(vector<int>& bloomDay, int m, int k) {
if((long)m*k>bloomDay.size()) return -1;
int left = 1; int right = *max_element(bloomDay.begin(),bloomDay.end());
while(left<right){
int mid = (left+right)/2;
int cur = 0;//当前天数下收集到的花束
int sum = 0;//当前积累的花朵
for(int i=0;i<bloomDay.size();i++){
if(bloomDay[i]<=mid) sum++;
else sum = 0;
if(sum==k) sum=0,cur++;
}
if(cur>=m) right = mid;//相等也要往下取,取下界
else left = mid + 1;
}
return right;
}
};
18. 可以到达的最远建筑
二分+前缀和优化+优先队列
class Solution {
public:
int furthestBuilding(vector<int>& heights, int bricks, int ladders) {
if(ladders>=heights.size()-1) return heights.size()-1;//梯子数量足够
int left = 0; int right = heights.size()-1;
//预先计算楼梯差值
vector<int> need(heights.size());
vector<int> index(heights.size());//优化,记录到目前为止最大落差位置
vector<long> presum(heights.size());//前缀和优化计算
int max_ = INT_MIN;
//预计算,优化记录
for(int i=1;i<heights.size();i++){
need[i] = heights[i]-heights[i-1]>0?heights[i]-heights[i-1]:0;
presum[i] = presum[i-1] + need[i];//前缀和
}
while(left<right){
int mid = (left+right+1)/2;//mid是当前终点
if(mid<=ladders){ left = mid;continue;}
long sum = presum[mid];//爬到终点的总代价
priority_queue<int> q;//大顶堆找前n个最大值
for(int i=1;i<=mid;i++)
q.push(need[i]);
for(int i=0;i<ladders;i++){
sum = sum-q.top();
q.pop();
}
if(sum>bricks) right = mid-1;
else left = mid ;//尽可能跑远
}
return left;
}
};
19. 可移除字符的最大数目
二分法+暴力
class Solution {
public:
bool judge(string s,string &p){
int i=0; int j=0;
while(i<s.size()&&j<p.size()){
if(s[i]==p[j]) j++;
i++;
}
if(j==p.size()) return true;
return false;
}
int maximumRemovals(string s, string p, vector<int>& removable) {
int left = 0; int right = removable.size();//下标及以前的数都删除
while(left<right){
int mid = (left+right+1)/2;
string temp = s;
for(int i=0;i<mid;i++)
temp[removable[i]] = '#';
if(judge(temp,p)) left = mid;//满足条件也要往上取
else right = mid-1;
}
return left;
}
};
20. 最小化数组中的最大值
二分+贪心+滚动变量优化
class Solution {
public:
int minimizeArrayValue(vector<int>& nums) {
long long sum = accumulate(nums.begin(),nums.end(),0ll);
long left = sum/nums.size(); long right = *max_element(nums.begin(),nums.end());
while(left<right){
long mid = (left+right)/2;
long trans = 0;
long long cur;
for(int i=nums.size()-1;i>0;i--){
cur = (long)nums[i]+trans;
trans = cur>mid?cur-mid:0;
}
if(nums[0]+trans>mid) left = mid+1;
else right = mid;
}
return right;
}
};
21. 最小化数组中的最大值
点击查看代码