华为 | 机考 | 100分题【最短木板长度】

在这里插入图片描述
■ 题目描述

【最短木板长度】

小明有 n 块木板,第 i ( 1 ≤ i ≤ n ) 块木板长度为 ai。
小明买了一块长度为 m 的木料,这块木料可以切割成任意块,
拼接到已有的木板上,用来加长木板。
小明想让最短的模板尽量长。
请问小明加长木板后,最短木板的长度可以为多少?

# -*- coding:utf-8 -*-
"""
流程分析:
1. 只有一个板子的时候直接加;
2. 有2个板子的时候:
    短板+m <= 长板 时 => min_len = 短板+m;
    短板+m>长版 时 => min_len = 长版+(m-(长版-短板))//2
3. 超过2个板子
    从最小阶级差开始,一层一层计算:
        可能一根都补不齐;
        可能满足一部分;
        可能补到当前最高板子还多;
"""
from collections import Counter


def compute_min_len(n, m):
    if len(n) == 1:
        return n[0] + m
    elif len(n) == 2:
    	# 排序用于区分大小值
        n1 = sorted(n)
        # 两板长度差距
        p_dis = n1[1] - n1[0]
        if m <= p_dis:
            return n1[0] + m
        else:
            return n1[1] + (m - (n1[1] - n1[0])) // 2
    else:
    	# 排序用于区分大小值 Set用于更好的区分不同长度板子的差异
        set_n = sorted(list(set(n)))
        # Counter能更好的计算不同板长的数量 用于后续补平计算
        counter_n = Counter(n)
        i = 0
        min_len = set_n[0]
        while i < len(set_n) - 1:
        	# 两板长度差距
            p_dis = set_n[i + 1] - set_n[i]
            # 短板数量
            p_count = counter_n[set_n[i]]
            # m 是否能补平所有短板
            if m // p_count <= p_dis:
                if m // p_count >= 1:
                    min_len += m // p_count
                else:
                    min_len
                m = 0
                break
            else:
                min_len = set_n[i] + p_dis
                counter_n[set_n[i + 1]] += p_count
                m -= p_dis * counter_n[set_n[i]]
                del counter_n[set_n[i]]
            i += 1
        # m 板很长,补平所有板到最高时,还能继续加板长
        if m:
            min_len += m // counter_n[set_n[-1]]
    return min_len


# Test Cases Part.
# Only 1
n, m = [1], 110
min_len = compute_min_len(n, m)
print(min_len, min_len == 111)

# Only 2 补不平
n, m = [1, 103], 100
min_len = compute_min_len(n, m)
print(min_len, min_len == 101)

# Only 2 补平超
n, m = [1, 103], 110
min_len = compute_min_len(n, m)
print(min_len, min_len == 107)

# Multi 无补平
n, m = [1, 1, 5, 7, 8, 18], 1
min_len = compute_min_len(n, m)
print(min_len, min_len == 1)

# Multi 部分补平
n, m = [1, 1, 5, 7, 8, 18], 2
min_len = compute_min_len(n, m)
print(min_len, min_len == 2)

n, m = [1, 1, 5, 7, 8, 18], 10
min_len = compute_min_len(n, m)
print(min_len, min_len == 5)

# Multi 超过
n, m = [1, 1, 5, 7, 8, 18], 100
min_len = compute_min_len(n, m)
print(min_len, min_len == 23)



🎉如果对你有所帮助,可以点赞、关注、收藏起来,不然下次就找不到了🎉


【点赞】⭐️⭐️⭐️⭐️⭐️
【关注】⭐️⭐️⭐️⭐️⭐️
【收藏】⭐️⭐️⭐️⭐️⭐️

Thanks for watching.
Kenny

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

比特本特

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值