返回

只用 O(1) 空间移除装有非法货物的汽车的最短时间

后端

LeetCode 2167:Minimum Time to Remove All Cars Containing Illegal Goods

题目

有一排汽车停在一条高速公路上,每辆汽车都可能装有非法货物。给你一个下标从 0 开始的整数数组 cars ,其中 cars[i] 的值为 0 表示第 i 辆汽车没有装载非法货物,值为 1 表示第 i 辆汽车装有非法货物。

你还将获得一个整数 k ,表示最多可以检查多少辆汽车。一旦检查发现一辆汽车装有非法货物,就会立即移除这辆汽车。

你可以从队伍的任意一侧开始检查。每当你检查一辆汽车并将其移除后,队伍会立即自动向前移动,使排在该汽车后面的汽车依次向前移。

请你返回移除所有装有非法货物的汽车的最短时间。

示例 1

输入:cars = [0,1,1,0,1], k = 3
输出:2
解释:
第一趟检查,检查3辆汽车并移除2辆,时间为1。
第二趟检查,检查2辆汽车并移除1辆,时间为1。
所有装有非法货物的汽车都被移除了。

示例 2

输入:cars = [0,0,1,1,1,0], k = 2
输出:3
解释:
第一趟检查,检查2辆汽车并移除2辆,时间为1。
第二趟检查,检查3辆汽车并移除1辆,时间为2。
所有装有非法货物的汽车都被移除了。

思路分析

我们可以用一个动态规划的算法来解决这个问题。

首先,我们定义状态 dp[i][j] 为从第 i 辆车开始检查,最多检查 j 辆车,移除所有装有非法货物的汽车的最短时间。

然后,我们可以用以下公式来计算 dp[i][j]:

dp[i][j] = min(dp[i+1][j], dp[i+k][j-k] + 1)

其中,dp[i+1][j] 表示从第 i+1 辆车开始检查,最多检查 j 辆车,移除所有装有非法货物的汽车的最短时间。

dp[i+k][j-k] + 1 表示从第 i+k 辆车开始检查,最多检查 j-k 辆车,移除所有装有非法货物的汽车的最短时间,再加上检查第 i 到第 i+k-1 辆车的最小时间(即 1)。

我们只需要从左到右计算出 dp[0][j] (j <= cars.length) 的值,就能得到问题的解。

代码实现

def min_time_to_remove_illegal_cars(cars, k):
  """
  :type cars: List[int]
  :type k: int
  :rtype: int
  """
  # 特判
  if not cars or k <= 0:
    return 0

  n = len(cars)
  # dp[i][j] 表示从第 i 辆车开始检查,最多检查 j 辆车,移除所有装有非法货物的汽车的最短时间
  dp = [[float('inf')] * (k + 1) for _ in range(n)]

  # 初始化
  for i in range(n-1, -1, -1):
    dp[i][0] = 0

  # 计算 dp[i][j]
  for i in range(n-2, -1, -1):
    for j in range(1, k + 1):
      dp[i][j] = min(dp[i+1][j], dp[i+k][j-k] + 1)

  return dp[0][k]

时间复杂度

时间复杂度为 O(nk),其中 n 是汽车的数量,k 是最多可以检查的汽车的数量。

空间复杂度

空间复杂度为 O(nk),其中 n 是汽车的数量,k 是最多可以检查的汽车的数量。

结语

我们使用了动态规划的方法,在 O(1) 的空间复杂度下解决了这个问题。动态规划是一种非常强大的算法,可以解决很多复杂的问题。希望这篇文章对您有所帮助!