面试高频算法题补充系列:木棍切割问题

前言

了解更多常考高频算法题可以关注
公众号:一个搬砖的胖子
高频算法网站:https://codetop.cc/
小程序:CodeTop

此题经常在字节跳动后端面试中遇到,尤其是教育部门的三面。我押一包辣条,之后面试还会考察这道题。

题目描述

给定长度为n的数组,每个元素代表一个木头的长度,木头可以任意截断,从这堆木头中截出至少k个相同长度为m的木块。已知k,求max(m)。

输入两行,第一行n, k,第二行为数组序列。输出最大值。

输入

5 5

4 7 2 10 5

输出

4

解释:如图,最多可以把它分成5段长度为4的木头
在这里插入图片描述

ps:数据保证有解,即结果至少是1。

题目分析

方法一:暴力。大概思路就是从1遍历到木棍最长的长度,每次遍历的长度作为m,如果可以将所有木头截出来k个长度为m的木块,则更新最大值,最后输出最大值即可。可以通过下面的伪代码片段辅助理解:

// input n, k;
int maxV = max(a[0 ~ n - 1]);
int res = 0;
while (1 <= maxV)
{
    int cnt = 0;
    for (int i = 0; i < n; i ++ ) cnt += a[i] / m;
    if (cnt >= k) res = max(res, cnt);  // 如果当前可以截出来超过k段,就更新结果
    m ++;
}

cout << res << endl;

时间复杂度也很容易看出来是O(n * len), len为木头中最大的长度。容易想到遍历长度时可以从大到小遍历,if (cnt >= k)成立,则该值即为最终结果,可直接break,但最坏时间复杂度没变。

方法二:二分。方法一在[1,max]寻找最大长度时是顺序遍历,由于其有序,我们可借助二分来快速检出结果。如果能截出来k个长度为x的木块,说明答案肯定 >= x,则接下来只需在[x,max]中找m最大满足条件的长度。反之则说明答案 < x,则在[1,x-1]中寻找结果。这样我们每次可以舍弃1/2的情况,因此使用二分的时间复杂度是O(n * log Len)。

#include <iostream>
using namespace std;

const int N = 100010;
int a[N];
int n, k;
int check(int mid)
{
    int res = 0;
    for (int i = 0; i < n; i ++ ) res += a[i] / mid;
    return res;
}
int main()
{
    cin >> n >> k;
    int l = 1, r = -1;
    for (int i = 0; i < n; i ++ )
    {
        cin >> a[i];
        r = max(r, a[i]);
    }
    while (l < r)
    {
        int mid = l + r + 1 >> 1;
        if (check(mid) >= k) l = mid;
        else r = mid - 1;
    }
    cout << l << endl;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值