贪心算法解决小船问题

27 篇文章 0 订阅

 小船问题:

有一个数组arr,每个数代表每一个坐船人的体重,还有一个limit,代表小船的最大载重,每艘船限坐两人,求最少要多少船。

对问题进行分析,首先,我们对数组进行排序,先考虑两种极端情况;

如果数组最小值大于船最大载重的一半,那么说明不能进行两人合坐一艘船的情况。直接返回数组的长度;

如果数组的最大值小于等于船最大载重的一半,那么说明任何两个人都可以合坐一艘船,直接返回数组长度的一半。(因为要向上取整,可以直接  return  (arr.length + 1)/2 ;)

对于一半的情况,我们需要对数组进分组处理,将其分为大于limit / 2(记为A) 和小于等于 limit / 2(记为B),对A数组进行从小到大的遍历,对B数组进行从大到小的遍历;

将A,B两数组提取出来的结果进行取和,若和小于limit,则lessUsed++;(lessUsed表示分别在A,B两个不同的数组,但可以两人合坐一条船的数量)

若和大于limit,则将A数组左移,同时lessUnused++;(lessUnused表示在B数组,但是无法和A数组的人一起合坐,只能和B组合坐一条船的人)

最后,A组剩下的人,可以用arr.length - lessR - 1 -lessUsed表示。

在A或B任何一个数组到达尽头时,我们将可以lessUsed, (lessUnused +1)/ 2 ,和A数组剩下的数据加在一起返回即可。

 public static int minBoat(int []arr ,int limit){
        //  对arr 进行排序
        if (arr == null || arr.length == 0){
            return  0;
        }

        if (arr[arr.length -1] <= limit/2 ){  // 如果任何人的体重小于等于船的一半,说明任何人可以两两坐船。
            return (arr.length + 1)/2;
        }

        if (arr[0] > limit/2){   //如果所有人的体重大于船的一半,说明无法一起坐。
            return arr.length;
        }

        int lessR = -1;
        for (int i = arr.length -1 ;i >= 0; i--){
            if (arr[i] <= (limit /2)){
                lessR = i;
                break;
            }
        }

        int L = lessR;
        int R = lessR +1;
        int lessUnused = 0;
        while(L >= 0){
            int solved = 0;
            while(R < arr.length && arr[L] + arr[R] <= limit){
                R++;
                solved++;
            }
            if (solved == 0){
                lessUnused++;
                L--;
            }else {
                L = Math.max(-1, L-solved);
            }
        }

        int lessAll = lessR +1;
        int lessUsed = lessAll - lessUnused;
        int moreUnsolved = arr.length - lessR - 1 -lessUsed;
        return  lessUsed + ((lessUnused + 1) >> 1) + moreUnsolved;
      }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值