leetcode--Boats to Save People

题目:给定数组表示人的重量,现在用船去救这些人,每条小船载重限制为limit,最多坐两个人,求最少需要多少条小船?

分析:
(1)假如一开始就知道了这道题是使用贪心策略,其实还比较简单。最大最小的匹配尝试并证明一下就行了。但是一开始,不太容易往贪心上考虑。
(2)先来看看暴力破解,我们可以尝试将所有的people两人一组组队,这样一共会有大约(n-1)(n+1)/4中组队的情况,这里排列组合就不详细分奇偶讨论了。组队完成后,将不满足要求的组合拆开,看看最后哪种组合剩下的队伍最少。这样组队其实复杂度相当高。
(3)我们看看这个过程里都有哪些多余的步骤可以简化算法:

  • 第一点,对于那些大于limit/2的people,彼此之间是无法组队的
  • 基于第一点,我们考虑到较大的数字选择其实比较少,对于它们我们可以先考虑。而对于那些不大于limit/2的数字,任意组合都没有问题。
  • 现在为一个最大的不超过limit的元素挑选队友,想到这里,贪心策略就不是很突兀了,我想试试会不会那些不超过limit的最大的数字,和当前未匹配的最小的数字组合就是答案呢?

证明:假设max是小于limit的最大数字,min是所有元素中最小的数字,如果 m a x + m i n l i m i t max+min \leq limit 则它们搭配是最优的。
反证法:假设存在更优的情况,max,和min没有搭配在一起。

  • 首先在这个最优解中,这两个人不能落单,否则将它们组合在一起,情况不会变差。
  • 假设最有组合中,max与x组合,min与y组合;那么有
    m a x + x l i m i t max+x \leq limit
    m a x y max \geq y 是已知的。所以
    y + x l i m i t y+x \leq limit
    也成立。
    到这里,假如我们将最优组合中的(max,x)(min,y)换成(max,min)(x,y)同样是一个最优解。
    所以最大最小的搭配能够产生最优解。其实,只要让那些能匹配的大值元素不落单,都是最优解。
    时间复杂度:
    最大最小搭配需要排序,排序后两个指针双向遍历即可。
    复杂度: O ( n l o g n ) O(nlogn)
    代码:
 public int numRescueBoats(int[] people, int limit) {
	        int rs = people.length;
	        Arrays.sort(people);
            int pre = 0,latter = people.length-1;
            while(pre<latter){
                if(people[latter--]+people[pre]<=limit){
                    pre++;
                    rs--;
                }
            }
	        return rs;
	    }

猜你喜欢

转载自blog.csdn.net/weixin_32931837/article/details/88692421