← 返回题目列表

救生艇问题如何用贪心求最少船数?(LeetCode 881)

高频 中等 第 10 / 29 题 更新于 2026/07/30
贪心双指针排序配对

简化版

先按体重排序,每次让最重的人上船;如果最轻的人能和他同船,就一起走,否则最重的人单独走。

这是最优的,因为最重的人迟早要占一条船,把他和当前最轻的人配对不会浪费更好的机会。

详细版

排序后用双指针 l 指向最轻的人,r 指向最重的人。每轮一定安排 people[r] 上船。如果 people[l] + people[r] <= limit,说明最轻可以和最重同船,l++;无论是否配对,最重都已上船,所以 r--,船数加 1。

int numRescueBoats(int[] people, int limit) {
    Arrays.sort(people);
    int l = 0, r = people.length - 1;
    int ans = 0;
    while (l <= r) {
        if (people[l] + people[r] <= limit) l++;
        r--;
        ans++;
    }
    return ans;
}

如果最轻的人都不能和最重的人同船,那么任何其他人更重,也不可能和最重的人同船,最重只能单独走。如果能配,则把最轻的人带走一定不吃亏。

完整版教学

一、为什么先处理最重的人

每条船最多坐两个人,且有重量上限。最重的人是最难安排的,因为他能搭配的人最少。如果不先安排他,后面只会剩下更有限的选择,不会凭空变容易。

贪心中经常要先处理「约束最紧」的对象。救生艇里约束最紧的就是最重的人:他不能被拆分,也不能和超过限制的人同船,所以每轮先决定他的归宿。

二、为什么尝试搭配最轻的人

当最重的人 H 上船时,能和他同船的人必须满足 weight + H <= limit。排序后,最轻的人 L 是最容易满足这个条件的候选。如果连 L + H 都超过限制,那么其他任何人都不可能和 H 同船。

如果 L + H <= limit,把最轻的人和最重的人配在一起不会变差。因为最轻的人对任何船都是最容易安插的,他和最重的人同船可以节省一个位置,同时不会抢走其他人更需要的轻量伙伴。

三、交换论证证明贪心安全

假设存在一个最优方案中,最重的人 H 没有和当前最轻的人 L 坐同一条船。如果 H 单独坐,而 L 和别人坐,那么把 L 挪去和 H 坐,不会超重,船数不增加。如果 H 和另一个人 X 坐,且 L <= X,那么把 X 换成 L 也不会超重。

这说明当 L + H <= limit 时,总存在一个最优方案让 LH 同船。因此贪心配对是安全的,不会排除最优解。

四、数字例子完整走查

people = [3,2,2,1]limit = 3 为例,排序后是 [1,2,2,3]

l 指向r 指向判断船数
131+3>3,3 单独走1
121+2<=3,1 和 2 同船2
22剩下 2 单独走3

答案是 3。注意第一轮最轻的 1 都无法和 3 同船,所以 3 不可能和任何人同船。

五、流程示意

排序: [轻 ... 重]
       l       r

while l <= r:
  安排 people[r]
  如果 people[l] + people[r] <= limit:
      l++   // 最轻一起走
  r--       // 最重一定走
  boats++

这个流程每轮至少送走一个人,最多送走两个人。双指针不会回退,所以排序后扫描是线性的。

六、复杂度与边界

排序是主要成本,时间 O(n log n)。双指针扫描一次,空间取决于排序实现,额外变量是 O(1)。如果输入体重范围很小,可以用计数排序或桶计数优化排序成本,但面试里普通排序足够。

边界上,若只剩一个人,l == r 时仍然需要一条船。题目通常保证每个人体重不超过 limit,否则单人也无法上船,业务题中需要额外处理。

记忆钩子:最重的人每轮必须走;能带最轻就带,带不了谁都带不了。

七、常见误区与追问

  • 误区:优先让最轻的人配最重能配的人。 更稳定的视角是先固定最重的人,因为他选择最少。
  • 误区:一条船可以坐多人。 原题限制最多两人,这是双指针贪心成立的重要条件。
  • 误区:配不上最轻时还尝试中间的人。 中间的人更重,不可能比最轻更容易配上最重。
  • 追问:为什么配最轻不会影响最优? 可用交换论证,把最重原来的搭档换成更轻的人不会超重。
  • 追问:复杂度是多少? 排序 O(n log n),扫描 O(n),总时间 O(n log n)
  • 追问:如果船可坐任意多人呢? 问题会变成装箱类问题,当前简单贪心不再保证最优。

八、加强记忆

救生艇问题的锚点是「先安排最难安排的最重者」。每轮最重的人一定要上船;如果当前最轻的人能一起上,就把他带走,因为不会损害最优;如果最轻都带不了,最重只能单独走。排序让「最轻」和「最重」一眼可见,双指针让每个人只处理一次。记住「最重必走,最轻试配」,代码和证明都会自然出来。