算法设计与分析(七)

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)

Example1

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

Example 3:

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;
    }
};

猜你喜欢

转载自blog.csdn.net/Maple_Lai/article/details/83242240