给定一个数组arr,长度为N且每个值都是正数,代表N个人的体重。再给定一个正数 limit,代表一艘船的载重。

问题描述:

        给定一个数组arr,长度为N且每个值都是正数,代表N个人的体重。再给定一个正数 limit,代表一艘船的载重。

        以下是坐船规则:

  1. 每艘船最多只能做两人。
  2. 乘客 的体重和不能超过limit。

        返回如果同时让这N个人过河最少需要几条船。 

思想:

        首先把整个数组进行排序,若数组中出现大于limit的数字,则无法过河,直接返回-1。

普遍情况算法流程:

1.找到小于等于limit一半的数位置L,另一半指针为R= L+1。

2.从L开始和R位置的数进行配对。

        2.1 如果L位置的数和R位置上的数加起来大于limit,那么R位置保持不变,L位置向左移动一位,原本L位置的数字为X类型数字。

        2.2 如果L位置的数和R位置上的数加起来小于等于limit,那么移动R位置,查看R右半部分宫有几个数字和L位置数字匹配满足条件。我们就找到了一批匹配的数字,记录右部分移动了几位,左半部分也相应的移动几位。这类型的人员用√表示。

        2.3 在2.2中若右半部分找不到匹配的数字,则L向左移动一位,原本L位置的数字为X类型数字。

        2.4 最后结果可能分为两种情况:左侧先匹配完和右侧先匹配完。当左侧先匹配完时,右侧剩下的数字每个人一条船。当右侧先匹配完时,左侧剩下的每个人都是X类型。

3. X类型人员两人乘一艘船,√号类型人员左半部分和右半部分搭配乘一条船,右侧剩下的人员每个人乘一条船。最后的结果是这三类人员相加和。

代码:

    public static int minBost(int[] arr, int limit) {
        if (arr == null || arr.length == 0) {
            return 0;
        }
        int N = arr.length;

        if (arr[N - 1] > limit) {
            return -1;
        }
        int lessR = -1;
        //所有人的体重都不超过limit
        // <= limit/2  最右的位置
        for (int i = N - 1; i >= 0; i--) {
            if (arr[i] <= (limit / 2)) {
                lessR = i;
                break;
            }
        }
        if (lessR == -1) {
            return N;
        }

        int L = lessR;
        int R = lessR + 1;
        int noUsed = 0;//画X的数量统计
        while (L >= 0) {
            int solved = 0;//此时的[L],让R画过了几个数
            while (R < N && arr[L] + arr[R] <= limit) {
                R++;
                solved++;
            }
            //R来到不达标的位置
            if (solved == 0) {
                noUsed++;
                L--;
            } else {//此时的[L],让R画过的solved个数
                L = Math.max(-1, L - solved);
            }
        }
        //左半区总个数  <=limit/2的区域
        int all = lessR + 1;
        //画对号的量
        int used = all - noUsed;
        // >limit/2区域中,没搞定的数量
        int moreUnsolved = (N - all) - used;
        return used + ((noUsed + 1) >> 1) + moreUnsolved;
    }

    public static void main(String[] args) {
        int[] arr = {1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5};
        int weight = 6;
        System.out.println(minBost(arr, weight));
    }

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值