【算法】救生艇

79 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第20天,点击查看活动详情

题目

给定数组 people 。people[i]表示第 i 个人的体重 ,船的数量不限,每艘船可以承载的最大重量为 limit。

每艘船最多可同时载两人,但条件是这些人的重量之和最多为 limit。

返回 承载所有人所需的最小船数 。

解题思路

关键词:最小船数;最多两人;一艘船有最大限制;

关键信息:尽量船只少;可能一艘船只能坐一人;找最重和最轻在一起;

遍历数组找最大解法

该解法是遍历所有人并从剩余人数中找到另外最佳人选与其登船(保证体重在限定内)

  1. 先找到第一个登船的人,判断本人体重是否在限制内否则是一人等船。
  2. 从剩余人数中遍历查找最大体重的人与其登船(在限定内),选中了就标记人已经被选择。
  3. 采用Hash表记录被选走的人,用于在遍历过程会去查找该人是否已经被选择。
    public int numRescueBoats(int[] people, int limit) {
            // 最小船数 最多两人 
            int count = 0; // 总数
            int length = people.length; // 获取所有人数
            Map<Integer, Boolean> getes = new HashMap(); // 存储是否被选走的人
            for(int i = 0;i<length;i++){ // 遍历人员列表
                if(getes.get(i) != null && getes.get(i)) continue; // 如果本人被选择过了就跳过
                int weight = people[i]; // 用户重量
                if(weight >= limit){ // 只能一人上船就直接跳过选择一条船
                     count++; // 使用了一条船
                    continue;
                }
                int maxWeight = 0; // 选择到另外一个人最大重量
                int position = -1;
                for(int j = i + 1;j < length;j++){ // 遍历之后的人
                     Boolean result = getes.get(j);
                    if(result != null && result) continue; // 选取过的人略过
                    int weight2 = people[j];
                    if(weight2 + weight <= limit){ // 当重量小于等于时
                        if(weight2 > maxWeight){ // 再判断是否是当前最大可选重量
                            maxWeight = weight2; // 赋值
                            position = j;
                        }
                    }
                }
                if(position > 0){ // 有选中另外一个人 标记已选
                    getes.put(position,true);
                }
                count++;// 使用了一条船
               
            }
            return count;
    }

但很遗憾该算法效率过低在平台编译运行中显示时间超出限制,但思路方法是可以解题的。

API解法

API解法主要是先通过排序将数组从小到大排序体重便于后面算法搭配组合。

  1. 遍历规则中最常用的双指针方法:双指针分别指向数组头和尾。
  2. 当两个指针没有重合前进行循环遍历,两个人体重符合限制双指针都移动;若两个人体重超出条件只能移动右指针说明只能一个人坐船。
  3. 最后输出使用小船数量。
    public int numRescueBoats(int[] people, int limit) {
			int length = people.length;
             Arrays.sort(people);
             int count = 0;
             int left =0,right = length - 1;
             while(left <= right){
                if(people[left]+ people[right] <= limit){
                    left++;
                }
                right --; 
                count ++;
             }
             return count;
    }

目前看来先排序对于算法效率来说是较高的,后续遍历次数大幅下降。另外解题思路上更简洁干净。

参考