LeetCode 每日一题 881. 救生艇

339 阅读1分钟

这是我参与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 <= 50000
  • 1 <= people[i] <= limit <= 30000

方法一

借鉴了大佬的思路:

贪心 + 双指针:

思路:先将数组元素排序,从大元素开始遍历,若是这个大元素能带上此时最小的元素则将最小元素也带上;否则,就大元素自己一个人乘坐一艘船;

证明:

贪心证明思路:将一般性的最优解转化为贪心解;

  • 对于系统中某一时刻的最小元素a和最大元素b,在一般性的最优解中有如下几种情况:

    • a + b > limit,那么b只能自己单独乘船

    • a + b <= limit,那么有如下几种情况

        1. b单独乘船
        1. b带另一个元素c上船
        1. bcda
  • 对于1,不管此时a是单独还是和别人搭船,都可以把a放到b

  • 对于2,可以把c换成a

  • 对于3,根据a + b <= limitb + c <= limita + d <= limit,可以得到a + b <= limitc + 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)