这是我参与8月更文挑战的第26天,活动详情查看:8月更文挑战
881. 救生艇
第 i 个人的体重为 people[i],每艘船可以承载的最大重量为 limit。
每艘船最多可同时载两人,但条件是这些人的重量之和最多为 limit。
返回载到每一个人所需的最小船数。(保证每个人都能被船载)。
示例 1:
输入:people = [1,2], limit = 3
输出:1
解释:1 艘船载 (1, 2)
示例 2:
输入:people = [3,2,2,1], limit = 3
输出:3
解释:3 艘船分别载 (1, 2), (2) 和 (3)
示例 3:
输入:people = [3,5,3,4], limit = 5
输出:4
解释:4 艘船分别载 (3), (3), (4), (5)
提示:
1 <= people.length <= 500001 <= people[i] <= limit <= 30000
方法一
借鉴了大佬的思路:
贪心 + 双指针:
思路:先将数组元素排序,从大元素开始遍历,若是这个大元素能带上此时最小的元素则将最小元素也带上;否则,就大元素自己一个人乘坐一艘船;
证明:
贪心证明思路:将一般性的最优解转化为贪心解;
-
对于系统中某一时刻的最小元素
a和最大元素b,在一般性的最优解中有如下几种情况:-
a + b > limit,那么b只能自己单独乘船 -
a + b <= limit,那么有如下几种情况-
b单独乘船
-
b带另一个元素c上船
-
b带c,d带a
-
-
-
对于1,不管此时
a是单独还是和别人搭船,都可以把a放到b上 -
对于2,可以把
c换成a -
对于3,根据
a + b <= limit,b + c <= limit,a + d <= limit,可以得到a + b <= limit,c + d <= limit
所以,对于任意的最优解,我们都可以转化为贪心解;因此,这种贪心解法是正确的;
class Solution {
public int numRescueBoats(int[] people, int limit) {
int res = 0;
Arrays.sort(people);
for (int i = 0, j = people.length - 1; i <= j; j -- ) {
if (people[j] + people[i] <= limit) i ++;
res ++;
}
return res;
}
}
时间复杂度: O(n)
空间复杂度: O(1)