2021 04 28 更新
- 结合新的二分写法
- 直接看
check(m) == true
时,l = m
还是r = m
- l = m 时,之前的
m = l + (r - l + 1) / 2;
- r = m 时,之前的
m = l + (r - l) / 2;
- 理由如下
- 当
check(m) = true
,l = m
时 - 如果恰好
l = r - 1
,那么m = l + (r - l) / 2 = l
- 完了!循环还是跳不出来
- 当
- 因此新的代码
class Solution {
public:
int len;
int maxDistance(vector<int>& position, int m) {
sort(position.begin(), position.end());
len = position.back();
int l = 0, r = position.back() - position[0];
while(l < r){
int mid = l + (r - l + 1) / 2;
if(count(mid, position) >= m) l = mid;
else r = mid - 1;
}
return l;
}
int count(int d, vector<int>& position){
int ans = 1;
int cur = position[0];
for(int i = 1; i < position.size(); i ++){
if(position[i] - cur >= d){
cur = position[i];
ans ++;
}
}
return ans;
}
};
新套路
- 不建议最后返回l或者r,反而思路不够清晰
框架 - 让ans记录上一次符合check要求的mid,剩下什么都不用管了
while(l<=r){
m=l+(r-l)/2
if check1(m)
update ans
l=mid+1
else if check2(m)
update ans
r=mid-1
else ...可能有三种情况
}
return ans
class Solution {
public:
int maxDistance(vector<int>& position, int m) {
len = position.size();
sort(position.begin(), position.end());
int l=0, r=position[len-1]-position[0];
int ans=0;
while(l<=r){
int mid = l+(r-l)/2;
if(count(mid, position)>=m){
ans=mid;
l=mid+1;
}
else if(count(mid, position)<m){
r=mid-1;
}
}
return ans;
}
private:
int len;
int count(int d, vector<int>& position){
int ans=1;
int cur=position[0];
for(int i=1; i<len; i++){
if(position[i]-cur>=d){
cur=position[i];
ans++;
}
}
return ans;
}
};
原套路
-
问题转换一下
- 用count(d)表示:当最小的距离是d时,最多能够放的球的个数,目标就是去找count(d)==m时,最大的d
- 用二分思想:
- 当count(d)<m时,说明d太大了,有的球放不下
- 当count(d)>m时,说明d太小了,还有更多的球能放
- 但是,要注意这个问题不是去找满足
count(d)==m
的d,因为可能有很多种比如[1,2,3,4,5,999999]
中,只要d>5,就都满足m==2,我们的目标是找到这其中最大的d
-
最需要记住的套路
-
一般二分法
mid = l+(r-l)/2 , l = mid+1, r=mid-1
- 它的问题是,如果
l=0 r=1
那么会陷入死循环,一般的查找问题用它就够了
-
解决这个问题的套路有两种:
m = l + (r-l)/2 with l = m + 1 and r = m
m = r - (r-l)/2 with l = m and r = m - 1
- 这样的就能解决如(0,1)中,我想要mid=1跳出循环的需求
class Solution {
public:
int maxDistance(vector<int>& position, int m) {
len = position.size();
sort(position.begin(), position.end());
int l=0, r=position[len-1]-position[0];
while(l<r){
int mid = r-(r-l)/2;
if(count(mid, position)>=m)
l=mid;
else if(count(mid, position)<m){
r=mid-1;
}
}
return l;
}
private:
int len;
int count(int d, vector<int>& position){
int ans=1;
int cur=position[0];
for(int i=1; i<len; i++){
if(position[i]-cur>=d){
cur=position[i];
ans++;
}
}
return ans;
}
};