贪心题目:救生艇

文章目录

题目

标题和出处

标题:救生艇

出处:881. 救生艇

难度

5 级

题目描述

要求

给定数组 people \texttt{people} people,其中 peoplei \texttt{peoplei} peoplei 表示第 i \texttt{i} i 个人的体重。船的数量不限,每艘船可以承载的最大重量为 limit \texttt{limit} limit,每艘船最多可同时承载两人。

返回承载所有人所需的最小船数。

示例

示例 1:

输入: people = 1,2, limit = 3 \texttt{people = 1,2, limit = 3} people = 1,2, limit = 3

输出: 1 \texttt{1} 1

解释: 1 \texttt{1} 1 艘船载 (1, 2) \texttt{(1, 2)} (1, 2)。

示例 2:

输入: people = 3,2,2,1, limit = 3 \texttt{people = 3,2,2,1, limit = 3} people = 3,2,2,1, limit = 3

输出: 3 \texttt{3} 3

解释: 3 \texttt{3} 3 艘船分别载 (1, 2) \texttt{(1, 2)} (1, 2)、 (2) \texttt{(2)} (2) 和 (3) \texttt{(3)} (3)。

示例 3:

输入: people = 3,5,3,4, limit = 5 \texttt{people = 3,5,3,4, limit = 5} people = 3,5,3,4, limit = 5

输出: 4 \texttt{4} 4

解释: 4 \texttt{4} 4 艘船分别载 (3) \texttt{(3)} (3)、 (3) \texttt{(3)} (3)、 (4) \texttt{(4)} (4) 和 (5) \texttt{(5)} (5)。

数据范围

  • 1 ≤ people.length ≤ 5 × 10 4 \texttt{1} \le \texttt{people.length} \le \texttt{5} \times \texttt{10}^\texttt{4} 1≤people.length≤5×104
  • 1 ≤ peoplei ≤ limit ≤ 3 × 10 4 \texttt{1} \le \texttt{peoplei} \le \texttt{limit} \le \texttt{3} \times \texttt{10}^\texttt{4} 1≤peoplei≤limit≤3×104

解法

思路和算法

为了使承载所有人的船数最小,应使承载两人的船数最大化,优先考虑使用一艘船承载两人。

对于体重最小的人,应考虑将其与体重最大的人安排同一艘船,如果两人体重之和不超过 limit \textit{limit} limit 则安排同一艘船,否则将体重最大的人单独安排一艘船。理由如下。

  • 如果两人体重之和不超过 limit \textit{limit} limit,则体重最小的人可以与任何人乘坐同一艘船。将体重最小的人与体重最大的人安排同一艘船,可以用一艘船承载两人。如果将体重最小的人与体重不是最大的人安排同一艘船,则剩余的人当中不一定存在可以和体重最大的人安排同一艘船的人,因此不可能使用更少的船承载所有人,相反可能需要更多的船承载所有人。

  • 如果两人体重之和超过 limit \textit{limit} limit,则体重最大的人与其他任何一个人的体重之和都超过 limit \textit{limit} limit,因此无法将体重最大的人与其他任何人安排同一艘船,必须将体重最大的人单独安排一艘船。

上述策略为贪心策略。另一种证明贪心策略可以得到最小船数的方法如下。

根据上述策略,假设有四个人分别安排到两艘船上,四个人的体重分别是 w 1 w_1 w1、 w 2 w_2 w2、 w 3 w_3 w3 和 w 4 w_4 w4,满足 w 1 ≤ w 2 ≤ w 3 ≤ w 4 w_1 \le w_2 \le w_3 \le w_4 w1≤w2≤w3≤w4,则体重 w 1 w_1 w1 和 w 4 w_4 w4 的两个人安排同一艘船,体重 w 2 w_2 w2 和 w 3 w_3 w3 的两个人安排同一艘船, w 1 + w 4 ≤ limit w_1 + w_4 \le \textit{limit} w1+w4≤limit, w 2 + w 3 ≤ limit w_2 + w_3 \le \textit{limit} w2+w3≤limit。如果不将体重 w 1 w_1 w1 的人和体重 w 4 w_4 w4 的人安排同一艘船,则承载这四个人的船数非但不可能减少,反而可能增加,理由如下。

如果将体重 w 1 w_1 w1 的人和体重 w 2 w_2 w2 或 w 3 w_3 w3 的人安排同一艘船,则剩余两个人的体重之和一定大于等于 w 1 + w 4 w_1 + w_4 w1+w4。如果剩余两个人的体重之和小于等于 limit \textit{limit} limit 则可以将剩余两个人安排同一艘船,此时需要两艘船承载这四个人;如果剩余两个人的体重之和大于 limit \textit{limit} limit 则不能将剩余两个人安排同一艘船,此时需要大于两艘船承载这四个人。

实现方面,可以首先将数组 people \textit{people} people 按升序排序,然后使用双指针从两端向中间遍历数组,计算最小船数。用 left \textit{left} left 和 right \textit{right} right 表示双指针,初始时 left \textit{left} left 指向 people \textit{people} people 的首个元素, right \textit{right} right 指向 people \textit{people} people 的末尾元素,则初始时 left \textit{left} left 和 right \textit{right} right 分别指向 people \textit{people} people 的最小元素和最大元素。当 left ≤ right \textit{left} \le \textit{right} left≤right 时,执行如下操作。

  1. 如果 people left + people right ≤ limit \textit{people}\\textit{left} + \textit{people}\\textit{right} \le \textit{limit} peopleleft+peopleright≤limit,则可以将体重为 people left \textit{people}\\textit{left} peopleleft 和 people right \textit{people}\\textit{right} peopleright 的两个人安排同一艘船, left \textit{left} left 向右移动一位, right \textit{right} right 向左移动一位;否则,将体重为 people right \textit{people}\\textit{right} peopleright 的人单独安排一艘船, left \textit{left} left 保持不变, right \textit{right} right 向左移动一位。

  2. 将船数加 1 1 1。

遍历结束之后,即可得到最小船数。

代码

java 复制代码
class Solution {
    public int numRescueBoats(int[] people, int limit) {
        int boats = 0;
        Arrays.sort(people);
        int left = 0, right = people.length - 1;
        while (left <= right) {
            if (people[left] + people[right] <= limit) {
                left++;
            }
            right--;
            boats++;
        }
        return boats;
    }
}

复杂度分析

  • 时间复杂度: O ( n log ⁡ n ) O(n \log n) O(nlogn),其中 n n n 是数组 people \textit{people} people 的长度。将数组 people \textit{people} people 排序需要 O ( n log ⁡ n ) O(n \log n) O(nlogn) 的时间,排序之后使用双指针遍历数组需要 O ( n ) O(n) O(n) 的时间,因此时间复杂度是 O ( n log ⁡ n ) O(n \log n) O(nlogn)。

  • 空间复杂度: O ( log ⁡ n ) O(\log n) O(logn),其中 n n n 是数组 people \textit{people} people 的长度。排序需要 O ( log ⁡ n ) O(\log n) O(logn) 的递归调用栈空间。

相关推荐
Jasmine_llq9 小时前
《P8816 [CSP-J 2022] 上升点列》
数据结构·算法·贪心·排序·二维动态规划 dp·类背包状态转移
lvwangshu2 天前
字符串 题解
字符串·trie·题解·贪心·技巧·性质题·思维好题
Tisfy6 天前
LeetCode 2333.最小差值平方和:排序 + 数学计算(不用二分)
数学·算法·leetcode·题解·贪心·排序
伟大的车尔尼6 天前
贪心题目:单调递增的数字
贪心
Tisfy6 天前
LeetCode 3727.最大交替平方和:排序 (双指针可选)
算法·leetcode·题解·贪心·数组·排序
jyyyx的算法博客10 天前
机器人开箱子【贪心 + 模拟】
贪心·模拟
伟大的车尔尼13 天前
贪心题目:使绳子变成彩色的最短时间
贪心
Tisfy16 天前
LeetCode 0678.有效的括号字符串:O(n)+O(1)一次遍历
算法·leetcode·字符串·题解·贪心·括号匹配
伟大的车尔尼16 天前
贪心题目:坏了的计算器
贪心