Leetcode.881. 救生艇---双指针+贪心

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

题解:

本题核心思想就是贪心,只要把握好怎么去贪心,便可以很容易的解决本题。

首先在逻辑层面思考:

  • 由题可知,船有最大限重,且船最多可以坐两个人。那么先从局部贪心的角度思考,一艘船若能坐两个人绝不会让他坐一个人;再从全局贪心的角度去思考,为了让船的数量尽可能的少,能坐在一艘船上的两个人一定是重量和趋于最大限重的,即我们尽可能的去让体重较大的和体重较小的坐在一起,这样的话可以充分提高船只的利用率。

在代码层面如何实现呢?

  • 我们可以先对people数组从小到大进行排序,接着利用双指针的思想,头尾相接坐船即可,当然能够一起坐船自然是通过if判断其总和小于limit;一旦总和大于limit时,根据实际情况可知,此时只能让体重较大的再小一点才能符合题意 (因为体重较小的在每次坐船时由于自身重量的优势,一定能够坐上船) ,因此双指针中前者不动,后者向前移动;
  • 通过上述操作后,我们发现还有一些人没有坐上船,且可能会出现一艘船的limit刚好等于一个人的体重的情况,那么我们如何记录住这些人呢?这时我们可以采用逻辑删除思想,对坐上船的人专门进行记录即可,详情可见代码注释。

代码:

class Solution {
    
    
    public int numRescueBoats(int[] people, int limit) {
    
    
        int res = 0;  //需要船的数量
        Arrays.sort(people);  //排序
        int[] isDelete = new int[people.length];  //逻辑删除数组

        for(int i=0;i<isDelete.length;i++){
    
    
            if(people[i]==limit){
    
     //一旦人的体重刚好==limit,直接给他个船让他坐上走
                res++;   //需要的船+1
                isDelete[i] = 1; //代表坐上船了
            }
            else{
    
    
                isDelete[i] = 0;  //代表还没坐上
            }
        }

        int i=0,j=people.length-1;
        while(i<j){
    
      //一旦i,j碰面即双指针遍历结束了
            if(isDelete[i]==1){
    
    
                if(isDelete[j]==1){
    
      //都坐上了,那么直接继续遍历
                    i++;
                    j--;
                    continue;
                }
                else{
    
          //i坐上了,j没坐上,那么只让头部向后,尾部保持不动等待与他配对的‘体重较小的人’一起坐船
                    i++;
                    continue;
                }
            }
            if(isDelete[i]==0){
    
    
                if(isDelete[j]==1){
    
       //思想同上
                    j--;
                    continue;
                }
                else{
    
    
                //此为都没坐上的情况
                    if(people[i]+people[j] > limit){
    
      
                    //一旦选中的这俩人不能一起坐船,那么让体重较大的先去一边等着,去找体重稍微大的与体重较小的配对
                        j--;
                        continue;
                    }
                    else{
    
    
                    //可以一起坐船
                        res++;
                        isDelete[i] = 1;
                        isDelete[j] = 1;
                        i++;
                        j--;
                        continue;
                    }
                }
            }
        }

		//再遍历一次,找到还没坐上船的人,此时由于能配对的都配对上了,所以剩下的都是不能配对的,因此一人一条船即可
        for(int n=0;n<isDelete.length;n++){
    
    
           if(isDelete[n]==0){
    
    
               res++;
               isDelete[n] = 1;           
            }
        }

        return res;
    }
}

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/xiangguang_fight/article/details/120518016