算法设计与分析(七)

881. Boats to Save People

The i-th person has weight people[i], and each boat can carry a maximum weight of limit.

Each boat carries at most 2 people at the same time, provided the sum of the weight of those people is at most limit.

Return the minimum number of boats to carry every given person. (It is guaranteed each person can be carried by a boat.)

Example1

Input: people = [1,2], limit = 3
Output: 1
Explanation:1 boat (1, 2)

Example2

Input: people = [3,2,2,1], limit = 3
Output: 3
Explanation:3 boats (1, 2), (2) and (3)

Example3

Input:people = [3,5,3,4], limit = 5
Output: 4
Explanation: 4 boats (3), (3), (4), (5)

Note

  • 1 <= people.length <= 50000
  • 1 <= people[i] <= limit <= 30000

思路

贪心的问题通常有很多种解法,不通的解法效率也不同,有时候甚至能差几十几百倍。个人而言并不是很擅长贪心的题目,感觉这种类型的题目都很玄学。贪心没有通用的模板,思路对了,可能几分钟就能把核心的贪心代码写出来了,思路不对,搞个几小时都是正常的,更难受的是有些题目看上去有贪心解法,实际上并没有,你按贪心的思路去研究最后发现只是在浪费时间。

这道题的题意大致是把加起来和不超过limit的两个整数配对,不能配对的整数就单独成组,求最少能有几个分组。假如把船比喻成一个水壶的话,往里面倒两杯水,如果这两杯水的体积加起来越接近水壶容量limit的话,造成的空余“浪费”就越少。因此,我最初的想法是把两个和最大,且不超过limit的人配对在一起,事实证明这样的配对原则是正确的,现在的问题就是怎么实现“和最大”配对。

这道题目的贪心算法逻辑如下:

  1. 把人的重量按降序排序,因为这道题目人的个数people.length上限为50000,如果用O(n^2)的排序方法的话会出现超时,所以我用的是快排。
  2. 如果队列头能够和列队尾配对的话,即重量加起来不超过limit,那么就配对,并且把头尾的人移出队列。
  3. 如果队列头和队列尾不能配对的话,即即重量加起来不超过limit,那么队列头单独成组,移出队列。因为如果现有队列里最轻的人都不能和队列头配对,就证明队列里没人能够和队列头配对了,只能单独成组。
  4. 重复第2和第3两个步骤的判断过程,每次找出一个组,直到完成全部分组,队列被清空。

代码

class Solution {
public:
    void mySort(vector<int>& people, int head, int tail)
    {
      int i, j, mid;
      i = head;
      j = tail;
      mid = people[head];
      while (i < j)
      {
        while (people[j] < mid && i < j) j--;
        if (i < j) 
        {
          people[i] = people[j];
          i++;
        }
        while (people[i] >= mid && i < j) i++;
        if (i < j) 
        {
          people[j] = people[i];
          j--;
        }
      }
      people[i] = mid;
      if (head < i - 1)
        mySort(people, head, i - 1);
      if (i + 1 < tail)
        mySort(people, i + 1, tail);
    }

    int numRescueBoats(vector<int>& people, int limit) 
    {
      int ans, head, tail;

      //按降序排序
      mySort(people, 0, people.size() - 1);

      //双人匹配
      ans = 0;
      head = 0;
      tail = people.size() - 1;
      while (head <= tail)
      {
        if (people[head] + people[tail] <=limit && 
        	head != tail)	//如果头尾能够匹配,并且头尾指针不是同一个人,则头尾成组
        {
          head++;
          tail--;
          ans++;
        }
        else	//头尾不能匹配或者只剩一个人,则头单独成组
        {
          head++;
          ans++;
        }
      }

      return ans;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值