每日一练2023.5.23(补:2023.5.22)

题目:

给你一个长度为 n、下标从 0 开始的整数数组 numsnums[i] 表示收集位于下标 i 处的巧克力成本。每个巧克力都对应一个不同的类型,最初,位于下标 i 的巧克力就对应第 i 个类型。

在一步操作中,你可以用成本 x 执行下述行为:

  • 同时修改所有巧克力的类型,将巧克力的类型 ith 修改为类型 ((i + 1) mod n)th

假设你可以执行任意次操作,请返回收集所有类型巧克力所需的最小成本。

示例 1:

输入:nums = [20,1,15], x = 5
输出:13
解释:最开始,巧克力的类型分别是 [0,1,2] 。我们可以用成本 1 购买第 1 个类型的巧克力。
接着,我们用成本 5 执行一次操作,巧克力的类型变更为 [1,2,0] 。我们可以用成本 1 购买第 2 个类型的巧克力。
然后,我们用成本 5 执行一次操作,巧克力的类型变更为 [2,0,1] 。我们可以用成本 1 购买第 0 个类型的巧克力。
因此,收集所有类型的巧克力需要的总成本是 (1 + 5 + 1 + 5 + 1) = 13 。可以证明这是一种最优方案。

示例 2:

输入:nums = [1,2,3], x = 4
输出:6
解释:我们将会按最初的成本收集全部三个类型的巧克力,而不需执行任何操作。因此,收集所有类型的巧克力需要的总成本是 1 + 2 + 3 = 6 。

提示:

  • 1 <= nums.length <= 1000
  • 1 <= nums[i] <= 109
  • 1 <= x <= 109

题解

初始化和基本思路

我们需要考虑是否应该执行“修改所有巧克力的类型”的操作。如果我们不进行任何操作,那么总成本就是收集所有巧克力的原始成本,即数组 nums 中所有元素的和。

但是,有时进行一些操作可以降低总成本,比如当某些巧克力的收集成本较高,而通过操作将这些成本分布到费用较低的巧克力上,我们可能会减少总成本。

动态规划思想

为了实现最低成本,我们需要模拟将所有种类的巧克力进行最多 n 次操作,其中 n 是 nums 数组的长度。每次操作的成本是 x,并且在每次操作之后,我们需要重新评估收集各类巧克力的成本。

在进行每次操作后,对于每一类,我们计算其变为所有其他类型的成本,并取其中的最小值。

具体实现步骤
  1. 初始化一个长度为 n 的数组 dp,其中 dp[i] 表示收集第 i 类巧克力的最小花费。
  2. 将 nums 的初始值赋给 dp
  3. 对 n 次操作进行循环,每次更新 dp 数组。
  4. 在每次更新过程中,计算操作的累积成本,并更新 dp 数组。
  5. 最后,计算经过最多 n 次操作之后,收集所有种类巧克力的最小总成本。

流程图说明:

+---------------------------------------+
|  开始                                 |
+---------------------------------------+
|1. 初始化 dp 数组,与 nums 长度相同,    |
|   并将 dp[i] 初始化为 nums[i]。       |
+---------------------------------------+
|2. 对于最多 n 次操作(即 0 到 n-1 次操作),|
|   进行以下流程:                        |
|                                       |
|   +-----------------------------------+|
|   |3. 计算当前 dp 数组中每种类型的巧克力 |
|   |   在经过 j(当前操作次数)次操作后     |
|   |   的最小收集成本:                   |
|   |   a. 计算当前操作的花费 cost = j × x |
|   |   b. 对于每个巧克力类型 i,计算操作后  |
|   |      变成为其他类型的成本并更新 dp。   |
|   +-----------------------------------+|
+---------------------------------------+
|4. 计算所有操作后收集所有类型巧克力的最小    |
|   总成本,将 dp 数组中的所有元素相加。    |
+---------------------------------------+
|5. 结束                                 |
+---------------------------------------+

具体步骤解释:

  1. 开始:流程图从此处开始。
  2. 初始化 dp 数组:创建与 nums 数组长度相同的 dp 数组,并将 dp[i] 初始化为 nums[i]dp[i] 表示收集第 i 类型巧克力的最小花费。
  3. 进行 n 次操作
    • 对于每次操作:
      • 计算当前操作的总花费 cost = j × x,其中 j 是当前操作的次数。
      • 对于每种巧克力类型 i
        • 计算巧克力类型 i 变为其他类型的成本。
        • 更新 dp[i] 为当前操作后收集到第 i 类型巧克力的最小成本。
  4. 计算最小总成本:经过所有操作后,计算收集所有类型巧克力的最小总成本,即 dp 数组中所有元素的和。
  5. 结束:流程图结束。

代码实现

class Solution {
    public long minCost(int[] nums, int x) {
        int n = nums.length;
        long[] dp = new long[n];
        for (int i = 0; i < n; i++) {
            dp[i] = nums[i];  // 初始化dp数组,每个位置存储最初成本
        }

        long minTotalCost = 0;
        for (int cost : dp) {
            minTotalCost += cost;  // 初始的最小总成本就是不进行任何操作的情况
        }

        long currentTotalCost;
        for (int k = 1; k < n; k++) {
            // 计算一次操作后的累计成本
            for (int i = 0; i < n; i++) {
                dp[i] = Math.min(dp[i], nums[(i + k) % n] + k * x);
            }

            currentTotalCost = 0;
            for (long cost : dp) {
                currentTotalCost += cost;
            }

            // 更新最小总成本
            minTotalCost = Math.min(minTotalCost, currentTotalCost);
        }

        return minTotalCost;
    }
}
解释代码的核心部分:

  1. 初始化 dp 数组dp[i] 表示收集第 i 类巧克力的初始成本。
  2. 初始化最小总成本:将 nums 数组所有元素的和赋给 minTotalCost
  3. 模拟 n 次操作循环:对于每次操作,更新 dp 数组以记录最小成本。
  4. 更新 dp 数组:每次操作后,更新每一类巧克力的收集成本,考虑当前操作后的累积成本。
  5. 比较和更新最小总成本:每次操作后计算新的总成本,并与当前最小总成本比较,取最小值。

知识点解析:

知识点代码行数解释
数组声明与初始化3, 4定义并初始化数组 dp 以存储每种巧克力的最小成本。
初始总成本计算9-11计算不进行任何操作时收集所有巧克力的总成本。
for循环13-23使用 for 循环模拟最多 n 次操作。
条件判断与更新16-18在每次循环内更新 dp 数组以记录当前最小成本。
方法调用-使用辅助求解方法完成最优解。
贪心与动态规划思想整体代码通过贪心与动态规划的方法最小化收集所有巧克力的总成本。

2024.5.22

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值