返回介绍

lcp / LCP 12. 小张刷题计划 / README

发布于 2024-06-17 01:04:41 字数 4602 浏览 0 评论 0 收藏 0

LCP 12. 小张刷题计划

题目描述

为了提高自己的代码能力,小张制定了 LeetCode 刷题计划,他选中了 LeetCode 题库中的 n 道题,编号从 0n-1,并计划在 m 天内按照题目编号顺序刷完所有的题目(注意,小张不能用多天完成同一题)。

在小张刷题计划中,小张需要用 time[i] 的时间完成编号 i 的题目。此外,小张还可以使用场外求助功能,通过询问他的好朋友小杨题目的解法,可以省去该题的做题时间。为了防止“小张刷题计划”变成“小杨刷题计划”,小张每天最多使用一次求助。

我们定义 m 天中做题时间最多的一天耗时为 T(小杨完成的题目不计入做题总时间)。请你帮小张求出最小的 T是多少。

示例 1:

输入:time = [1,2,3,3], m = 2

输出:3

解释:第一天小张完成前三题,其中第三题找小杨帮忙;第二天完成第四题,并且找小杨帮忙。这样做题时间最多的一天花费了 3 的时间,并且这个值是最小的。

示例 2:

输入:time = [999,999,999], m = 4

输出:0

解释:在前三天中,小张每天求助小杨一次,这样他可以在三天内完成所有的题目并不花任何时间。

 

限制:

  • 1 <= time.length <= 10^5
  • 1 <= time[i] <= 10000
  • 1 <= m <= 1000

解法

方法一:贪心 + 二分查找

我们可以将题意转换为,将题目最多分成 $m$ 组,每一组去掉最大值后不超过 $T$ ,求最小的满足条件的 $T$。

我们定义二分查找的左边界 $left=0$,右边界 $right=\sum_{i=0}^{n-1}time[i]$,二分查找的目标值为 $T$。

我们定义函数 $check(T)$,表示是否存在一种分组方案,使得每一组去掉最大值后不超过 $T$,并且分组数不超过 $m$。

我们可以用贪心的方法来判断是否存在这样的分组方案。我们从左到右遍历题目,将题目耗时加入当前总耗时 $s$,并更新当前分组的最大值 $mx$。如果当前总耗时 $s$ 减去当前分组的最大值 $mx$ 大于 $T$,则将当前题目作为新的分组的第一题,更新 $s$ 和 $mx$。继续遍历题目,直到遍历完所有题目。如果分组数不超过 $m$,则说明存在这样的分组方案,返回 $true$,否则返回 $false$。

时间复杂度 $O(n \times \log S)$,空间复杂度 $O(1)$。其中 $n$ 和 $S$ 分别为题目数量和题目总耗时。

class Solution:
  def minTime(self, time: List[int], m: int) -> int:
    def check(t):
      s = mx = 0
      d = 1
      for x in time:
        s += x
        mx = max(mx, x)
        if s - mx > t:
          d += 1
          s = mx = x
      return d <= m

    return bisect_left(range(sum(time)), True, key=check)
class Solution {
  public int minTime(int[] time, int m) {
    int left = 0, right = 0;
    for (int x : time) {
      right += x;
    }
    while (left < right) {
      int mid = (left + right) >> 1;
      if (check(mid, time, m)) {
        right = mid;
      } else {
        left = mid + 1;
      }
    }
    return left;
  }

  private boolean check(int t, int[] time, int m) {
    int s = 0, mx = 0;
    int d = 1;
    for (int x : time) {
      s += x;
      mx = Math.max(mx, x);
      if (s - mx > t) {
        s = x;
        mx = x;
        ++d;
      }
    }
    return d <= m;
  }
}
class Solution {
public:
  int minTime(vector<int>& time, int m) {
    int left = 0, right = 0;
    for (int x : time) {
      right += x;
    }
    auto check = [&](int t) -> bool {
      int s = 0, mx = 0;
      int d = 1;
      for (int x : time) {
        s += x;
        mx = max(mx, x);
        if (s - mx > t) {
          s = x;
          mx = x;
          ++d;
        }
      }
      return d <= m;
    };
    while (left < right) {
      int mid = (left + right) >> 1;
      if (check(mid)) {
        right = mid;
      } else {
        left = mid + 1;
      }
    }
    return left;
  }
};
func minTime(time []int, m int) int {
  right := 0
  for _, x := range time {
    right += x
  }
  return sort.Search(right, func(t int) bool {
    s, mx := 0, 0
    d := 1
    for _, x := range time {
      s += x
      mx = max(mx, x)
      if s-mx > t {
        s, mx = x, x
        d++
      }
    }
    return d <= m
  })
}
function minTime(time: number[], m: number): number {
  let left = 0;
  let right = time.reduce((a, b) => a + b);
  const check = (t: number): boolean => {
    let s = 0;
    let mx = 0;
    let d = 1;
    for (const x of time) {
      s += x;
      mx = Math.max(mx, x);
      if (s - mx > t) {
        s = x;
        mx = x;
        d++;
      }
    }
    return d <= m;
  };
  while (left < right) {
    const mid = (left + right) >> 1;
    if (check(mid)) {
      right = mid;
    } else {
      left = mid + 1;
    }
  }
  return left;
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文