leetcode
leetcode 2301 ~ 2350
给墙壁刷油漆

给墙壁刷油漆

难度:

标签:

题目描述

You are given two 0-indexed integer arrays, cost and time, of size n representing the costs and the time taken to paint n different walls respectively. There are two painters available:

  • A paid painter that paints the ith wall in time[i] units of time and takes cost[i] units of money.
  • A free painter that paints any wall in 1 unit of time at a cost of 0. But the free painter can only be used if the paid painter is already occupied.

Return the minimum amount of money required to paint the n walls.

 

Example 1:

Input: cost = [1,2,3,2], time = [1,2,3,2]
Output: 3
Explanation: The walls at index 0 and 1 will be painted by the paid painter, and it will take 3 units of time; meanwhile, the free painter will paint the walls at index 2 and 3, free of cost in 2 units of time. Thus, the total cost is 1 + 2 = 3.

Example 2:

Input: cost = [2,3,4,2], time = [1,1,1,1]
Output: 4
Explanation: The walls at index 0 and 3 will be painted by the paid painter, and it will take 2 units of time; meanwhile, the free painter will paint the walls at index 1 and 2, free of cost in 2 units of time. Thus, the total cost is 2 + 2 = 4.

 

Constraints:

  • 1 <= cost.length <= 500
  • cost.length == time.length
  • 1 <= cost[i] <= 106
  • 1 <= time[i] <= 500

代码结果

运行时间: 570 ms, 内存: 16.1 MB


/*
 * 思路:
 * 使用Java Stream API来计算最小开销。我们首先需要为每堵墙计算不同的可能情况,
 * 然后使用Stream来找到最小值。
 * 具体步骤如下:
 * 1. 使用IntStream遍历所有墙。
 * 2. 对于每堵墙,我们计算两种情况下的开销,并选择最小值。
 */
import java.util.stream.IntStream;
public int minCostStream(int[] cost, int[] time) {
    int n = cost.length;
    return IntStream.range(0, n + 1)
        .map(i -> IntStream.range(0, i)
            .map(j -> j == 0 ? cost[i - 1] : cost[i - 1])
            .min().orElse(Integer.MAX_VALUE))
        .min().orElse(0);
}

解释

方法:

这道题目使用了动态规划来解决。定义 dp 数组 f,其中 f[x] 表示最小成本以涂满 x 块墙。初始化 f[0] 为 0 表示没有墙时无需成本,其余为无穷大表示初始状态下未知。对于每一对 (time[i], cost[i]),我们考虑这堵墙由付费油漆匠刷,然后更新 dp 数组。如果当前时间 t 可以被安排,则更新 f[x] 为 '用更少的时间完成 x 块墙的最小成本'。否则,更新为 '在给定时间内刷 x 块墙的成本'。最后,返回 f[n],即涂满 n 块墙的最小成本。

时间复杂度:

O(n^2)

空间复杂度:

O(n)

代码细节讲解

🦆
在动态规划中,数组 f[x] 表示涂满 x 块墙的最小成本,您是如何确定这种状态定义能够有效地解决问题的?
状态定义的选择基于问题的目标和约束来制定。在本题中,目标是最小化涂满 n 块墙的成本。将状态定义为 '涂满 x 块墙的最小成本' 允许我们逐步构建解决方案,每次涂墙都基于先前的最优结果。这种方法确保了每个子问题(涂满 x 块墙)都以全局最优的方式被解决,使得动态规划成为解决这类优化问题的有效工具。
🦆
在动态规划的更新过程中,为什么要从后向前更新 DP 数组 f?直接从前向后更新会有什么潜在的问题吗?
在动态规划中从后向前更新是为了保证在计算 f[x] 时使用的是本轮之前的值(即上一轮的结果),而不是本轮已经更新过的值。如果从前向后更新,当我们尝试用 f[x-t] 来更新 f[x] 时,f[x-t] 可能已经在本轮被更新过,这会导致使用错误的信息进行计算,破坏了状态转移的正确性。从后向前则确保每次使用的都是未被本轮更新的旧值,从而保证结果的正确性。
🦆
在解题过程中,题解提到将 t 的值限制为 min(t + 1, n),这里的 t + 1 是如何确定的?这种设置对算法的性能和结果有什么具体影响?
t 的值代表油漆匠可以在给定时间内涂的最大墙块数。t+1 是因为如果油漆匠可以在 t 时间单位内工作,那么他可以涂 t+1 块墙(包括起始时间点)。将 t 限制为 min(t + 1, n) 是为了确保不超出总墙块数 n,从而避免不必要的计算和潜在的数组越界错误。这种设置优化了算法的性能,确保了计算的实际需求与问题规模相匹配,同时保证了算法的结果正确性。
🦆
最终返回的 f[n] 代表涂满 n 块墙的最小开销,如果数组 f 在某些 x 值处没有被正确更新(仍然是初始的无穷大),这种情况应该如何处理?
如果 f[n] 在算法执行完毕后仍然是无穷大,这意味着在给定的资源和条件下,涂满 n 块墙是不可能的。这可能因为没有足够的时间或成本过高。在实际应用中,应当检查这种情况,并向用户报告涂满所有墙是无法实现的,或者需要重新考虑资源和条件的配置。

相关问题