二分+前缀和
看了几遍题目愣是没看明白,最后看的题解明白了!
题意就是按照 w [ i ] w[i] w[i] 的权重选取下标 i i i,这个问题可以转化成:所有小球连续排放在一条线上,下标 i i i 种类的球有 w [ i ] w[i] w[i] 个(相同种类的球是连续排放的),那么第 n n n 个球下标就为 n n n , n n n取值范围为 [ 1 , t o t a l ] [1,total] [1,total] t o t a l total total 为球总数。随机选取一个球然后判断球是哪个种类即可。
class Solution {
private:
vector<int> pre_sum;
public:
Solution(vector<int>& w) {
pre_sum.resize(w.size());
pre_sum[0] = w[0];
for(int i = 1; i < w.size(); i++) {
pre_sum[i] = pre_sum[i-1] + w[i];
}
}
int find(int x) {
int l = 0, r = pre_sum.size()-1;
while(l < r) { //最终l与r相遇于大于等于pre_sum[mid]的位置
int mid = l+r>>1;
if(pre_sum[mid] < x) l = mid+1;
else r = mid;
}
return l;
}
int pickIndex() {
int idx = rand()%pre_sum.back()+1;
return find(idx);
}
};
这里平方根取整,等同于最后一个使得 m i d ∗ m i d < = x mid*mid <= x mid∗mid<=x 的 m i d mid mid 。
class Solution {
public:
int mySqrt(int x) {
long long l = 0, r = x;
while(l < r) { //l与r最终在 mid*mid <= x 的mid位置相遇
long long mid = l+r+1>>1;
if(mid*mid <= x) l = mid; //停的位置性质是什么,看谁=mid所对应的判断条件
else r = mid-1;
}
return l;
}
};
二分
根据题意结合样例可以知道,求最小的速度 k k k 在至多 h h h 小时吃完。那么我们二分范围就是 [ 1 , 1 e 9 ] [1,1e9] [1,1e9] ,使用 c h e c k check check 判断 m i d mid mid 速度是否可以吃完,若可以我们就缩小范围即 r = m i d r = mid r=mid,反之 l = m i d + 1 l = mid + 1 l=mid+1 。
class Solution {
public:
bool check(vector<int> &piles, int &h, int &mid) {
int time = 0;
for(int num: piles) {
if(num%mid) time += num/mid + 1;
else time += num/mid;
}
return time <= h;
}
int minEatingSpeed(vector<int>& piles, int h) {
int l = 1, r = 1e9+5;
while(l < r) {
int mid = l + r >> 1;
if(check(piles,h,mid)) r = mid;
else l = mid + 1;
}
return l;
}
};