Leetcode 1552. Magnetic Force Between Two Balls 二分法


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) = truel = 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;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值