给定一个数组arr,长度为N且每个值都是正数,代表N个人的体重。再给定一个正数 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));
- }