[M贪心] lc881. 救生艇(贪心+贪心证明)
Posted Ypuyu
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[M贪心] lc881. 救生艇(贪心+贪心证明)相关的知识,希望对你有一定的参考价值。
1. 题目来源
链接:881. 救生艇
2. 题目解析
常规的一道贪心,思路很简单,关键仍旧是贪心思路的证明。
思路:
- 排序,尽量让重的和轻的组成一个救生艇。
- 即,每次都会将末尾最终的安排掉。
- 注意可能会造成
i=j
的情况,即最终仅剩余一人,那么只需要安排一条船即可。不论这个人的两倍是否大于limit
,无关紧要,反正他仅需一条船。 - 例如
people = [3,2,2,1], limit = 3
这个样例,最终a[i]=a[j]=2
,for
循环判出条件如果直接写成i<j
的话,就漏掉了 2 这个人,所以要写成i<=j
,反正不管如果,都只还要一条船来接 2。
证明:
- 证明思路仍旧:主要证明任给一个最优解可以通过调整,在答案不变差的情况下,调整为贪心解。
- 当记末尾人重为
d
,开头人重为a
。如果a+d>limit
,那么d
只能自己坐一艘船,和贪心解一致。 - 如果
a+d<=limit
。贪心解中,a、d
坐同一艘船,最优解有两种情况。d
自己坐一艘船。那么a
不论是自己坐一艘船还是和别人同坐另一艘船。调整a
和d
同坐,一定是更好的结果,结果不会变差。d
和其他人坐一艘船,假设为c
。显然此时,c>=a
,所以,不论a
自己坐,还是a
和别人坐,都可以将a、c
调换,让a
和d
坐同一艘船。并且重量是变少了,c
与a
的另一个人也少满足重量限制的。
- 综上,一定可以将最优解,在答案不变差的情况下,将坐船顺序调整为贪心解。那么贪心解就是一个最优解。
实现的时候,每次都安排末尾的人,所以尾指针顺次向前走就行。答案每次都 +1,不论是自己坐一艘船还是和前面的人坐一艘。注意循环跳出条件,i<=j
,原因在上面已经提过了。
- 时间复杂度: O ( n l o g n ) O(nlogn) O(nlogn)。
- 空间复杂度: O ( 1 ) O(1) O(1)
class Solution {
public:
int numRescueBoats(vector<int>& people, int limit) {
sort(people.begin(), people.end());
int res = 0;
for (int i = 0, j = people.size() - 1; i <= j; j -- ) {
if (people[j] + people[i] <= limit) i ++ ;
res ++ ;
}
return res;
}
};
以上是关于[M贪心] lc881. 救生艇(贪心+贪心证明)的主要内容,如果未能解决你的问题,请参考以下文章
LeetCode 881 救生艇[贪心 双指针] HERODING的LeetCode之路
LeetCode 797. 所有可能的路径(dfs) / 881. 救生艇(双指针,贪心) / 295. 数据流的中位数(对顶堆)