leetcode
leetcode 801 ~ 850
救生艇

救生艇

难度:

标签:

题目描述

代码结果

运行时间: 72 ms, 内存: 22.3 MB


/*
 * 思路:
 * 1. 将数组进行排序。
 * 2. 使用双指针,一个指向最轻的人,一个指向最重的人。
 * 3. 每次尝试将最轻和最重的人一起放到一艘船上,如果他们的重量和不超过限制,就将两个指针向内移动。
 * 4. 如果不能一起放到一艘船上,只将最重的人放到船上,指向最重的指针左移。
 * 5. 重复以上步骤直到所有人都被放到船上。
 */

import java.util.Arrays;

public class Solution {
    public int numRescueBoats(int[] people, int limit) {
        Arrays.sort(people);
        int[] pointers = {0, people.length - 1};
        int boats = 0;
        while (pointers[0] <= pointers[1]) {
            int i = pointers[0], j = pointers[1];
            if (people[i] + people[j] <= limit) {
                pointers[0]++;
            }
            pointers[1]--;
            boats++;
        }
        return boats;
    }
}

解释

方法:

此题解采用了计数排序和双指针技术来解决问题。首先,创建一个计数数组来存储每个可能的体重值的人数。然后初始化答案为人数总和,假设每个人都单独乘坐一艘船。使用双指针技术,一个指针从最轻的体重开始,另一个从最重的体重开始,尝试将两个体重的人配对乘坐同一艘船。如果可以配对,则减少相应的人数和所需的船数。当两个指针相遇时,停止配对,并检查最后剩余的同体重人是否可以成对乘坐。

时间复杂度:

O(n + limit)

空间复杂度:

O(limit)

代码细节讲解

🦆
在题解中,为什么选择使用计数排序而不是其他排序方式来处理`people`数组?
计数排序特别适用于当输入的数据范围(即体重范围)不是很大时,它的时间复杂度可以达到O(n+k),其中n是数组长度,k是数据的范围。由于体重的最大值限制为`limit`,使得计数排序的空间和时间效率非常高。此外,计数排序可以直接提供每个体重的人数,便于执行后续的双指针配对操作。
🦆
题解提到双指针从最轻和最重体重开始配对,如何确保两人的总体重不超过限制`limit`?
在双指针策略中,右指针`r`表示当前考虑的最重的体重,而左指针`l`表示最轻的体重。为了确保两人的总体重不超过`limit`,我们在配对前首先将右指针调整为`min(r, limit - l)`,这样可以保证即使最重的与最轻的人配对,其体重之和也不会超过`limit`。
🦆
当两个指针的体重之和恰好等于`limit`时,题解中是如何处理的?是否直接配对并移动指针,还是有其他的考虑?
当两个指针的体重之和恰好等于`limit`时,可以直接将这两个体重的人数对应减少,并且减少总需要的船数。然后根据消耗的人数更新左右指针,即如果左侧体重的人数不小于右侧体重的人数,则减少右侧体重的人数并左移右指针;反之,则减少左侧体重的人数并右移左指针。
🦆
为什么在双指针相遇时停止配对是正确的逻辑?这是否意味着没有更多有效的配对可能?
当双指针相遇时,意味着所有可能的体重组合已经尝试过配对。此时,剩余的同体重的人(若有)可以继续尝试是否可以两两配对。由于没有其他不同的体重可以配对,进一步的配对只能在相同体重的人中进行,这也是为什么要检查剩余相同体重人的配对情况。因此,双指针相遇时停止配对是有效且必要的,它确保了所有不同体重的配对机会都已经被尽可能利用。

相关问题