[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]=2for 循环判出条件如果直接写成 i<j 的话,就漏掉了 2 这个人,所以要写成 i<=j,反正不管如果,都只还要一条船来接 2。

证明:

  • 证明思路仍旧:主要证明任给一个最优解可以通过调整,在答案不变差的情况下,调整为贪心解。
  • 当记末尾人重为 d,开头人重为 a。如果 a+d>limit,那么 d 只能自己坐一艘船,和贪心解一致。
  • 如果 a+d<=limit。贪心解中,a、d 坐同一艘船,最优解有两种情况。
    • d 自己坐一艘船。那么 a 不论是自己坐一艘船还是和别人同坐另一艘船。调整 ad 同坐,一定是更好的结果,结果不会变差。
    • d 和其他人坐一艘船,假设为 c。显然此时,c>=a,所以,不论 a 自己坐,还是 a 和别人坐,都可以将 a、c 调换,让 ad 坐同一艘船。并且重量是变少了,ca 的另一个人也少满足重量限制的。
  • 综上,一定可以将最优解,在答案不变差的情况下,将坐船顺序调整为贪心解。那么贪心解就是一个最优解。

实现的时候,每次都安排末尾的人,所以尾指针顺次向前走就行。答案每次都 +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 救生艇(贪心)

Code皮皮虾贪心And双指针快速解题:881. 救生艇

Code皮皮虾贪心And双指针快速解题:881. 救生艇

LeetCode 881 救生艇[贪心 双指针] HERODING的LeetCode之路

LeetCode 797. 所有可能的路径(dfs) / 881. 救生艇(双指针,贪心) / 295. 数据流的中位数(对顶堆)

文巾解题 881. 救生艇