经典贪心双指针算法题:救生艇。几句话讲明白。

在这里插入图片描述
Leetcode题目链接

思路

先对数组排序,设一非递减的体重数组示例和初始双指针位置如下所示。

1099_2.png

观察首尾元素 people[ l l l] 和 people[ r r r]。记中间的任意数字为 mid,满足 1 ≤ \leq people[ l l l] ≤ \leq mid ≤ \leq people[ r r r] ≤ \leq limit。

  • 如果 people[ l l l] + people[ r r r] > target,则 mid + people[ r r r] > target,people[ r r r] 只能独自乘船,记录后令 r r r 左移。
  • 如果 people[ l l l] + people[ r r r] ≤ \leq target,则包括 people[ l l l] 的船有以下三种选择:
    • 只载 people[ l l l]
    • 载 people[ l l l] 与 people[ r r r]
    • 载 people[ l l l] 与某 mid
      从贪心思想出发,我们让 people[ l l l] 与还未上船中最大体重的 people[ r r r] 一起乘船是最优解。然后令 l l l 右移, r r r 左移。

此后循环这个过程并移动指针即可。

证明

记体重 a ≤ b ≤ c ≤ d ≤ e ≤ f a \leq b \leq c \leq d \leq e \leq f abcdef。且

  • a + f ≤ t a r g e t a + f \leq target a+ftarget
  • b + f ≤ t a r g e t b + f \leq target b+ftarget
  • c + f ≤ t a r g e t c + f \leq target c+ftarget
  • d + f > t a r g e t d + f > target d+f>target
  • e + f > t a r g e t e + f > target e+f>target

先分配最大的 f f f,可配对的有 a , b , c a, b, c a,b,c。将 f f f 与配对选项中最大的 c c c 分配在一起明显是最优解。但既然 c + f ≤ t a r g e t c + f \leq target c+ftarget,则

  • c + e ≤ t a r g e t c + e \leq target c+etarget
  • c + d ≤ t a r g e t c + d \leq target c+dtarget
  • b + f ≤ t a r g e t b + f \leq target b+ftarget
  • b + e ≤ t a r g e t b + e \leq target b+etarget
  • b + d ≤ t a r g e t b + d \leq target b+dtarget
  • b + c ≤ t a r g e t b + c \leq target b+ctarget

我们可直接分配 a , f a, f a,f 在一条船上,此后 b , c b, c b,c 一定能与其他人分配到一条船上(只要还有剩余)。

代码

仅提供 java 版本,多语言代码块可看这里

class Solution {
    public int numRescueBoats(int[] people, int limit) {
        Arrays.sort(people);

        int l = 0;
        int r = people.length - 1;
        int cnt = 0;

        while (l <= r) {
            if (people[l] + people[r] > limit) {
                cnt++;
                r--;
            } else {
                cnt++;
                l++;
                r--;
            }
        }

        return cnt;
    }
}

简化

class Solution {
    public int numRescueBoats(int[] people, int limit) {
        Arrays.sort(people);

        int l = 0;
        int r = people.length - 1;
        int cnt = 0;

        while (l <= r) {
            if (people[l] + people[r] <= limit)
                l++;
            cnt++;
            r--;
        }

        return cnt;
    }
}

复杂度

主要考虑排序

时间: Θ ( n ⋅ l o g   n ) \Theta(n\cdot log\ n) Θ(nlog n)
空间: Θ ( l o g   n ) \Theta(log\ n) Θ(log n)

推广

以下均为个人所著,兼顾了面试、本科、硕士阶段,包含清晰的 PPT 动画展示以及配套的练习题。读者也在陆续写其他算法教程。

  • 39
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值