leetcode
leetcode 2301 ~ 2350
收集巧克力

收集巧克力

难度:

标签:

题目描述

You are given a 0-indexed integer array nums of size n representing the cost of collecting different chocolates. The cost of collecting the chocolate at the index i is nums[i]. Each chocolate is of a different type, and initially, the chocolate at the index i is of ith type.

In one operation, you can do the following with an incurred cost of x:

  • Simultaneously change the chocolate of ith type to ((i + 1) mod n)th type for all chocolates.

Return the minimum cost to collect chocolates of all types, given that you can perform as many operations as you would like.

 

Example 1:

Input: nums = [20,1,15], x = 5
Output: 13
Explanation: Initially, the chocolate types are [0,1,2]. We will buy the 1st type of chocolate at a cost of 1.
Now, we will perform the operation at a cost of 5, and the types of chocolates will become [1,2,0]. We will buy the 2nd type of chocolate at a cost of 1.
Now, we will again perform the operation at a cost of 5, and the chocolate types will become [2,0,1]. We will buy the 0th type of chocolate at a cost of 1. 
Thus, the total cost will become (1 + 5 + 1 + 5 + 1) = 13. We can prove that this is optimal.

Example 2:

Input: nums = [1,2,3], x = 4
Output: 6
Explanation: We will collect all three types of chocolates at their own price without performing any operations. Therefore, the total cost is 1 + 2 + 3 = 6.

 

Constraints:

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

代码结果

运行时间: 73 ms, 内存: 16.4 MB


/*
 * 题目思路:
 * 使用Java Stream API来实现相同的逻辑。
 * 我们依然需要通过旋转巧克力的类型数组来找到最小的收集成本。
 */

import java.util.stream.IntStream;

public class ChocolateCollectionStream {
    public int minCost(int[] nums, int x) {
        int n = nums.length;
        int[] rotatedCosts = new int[n];
        System.arraycopy(nums, 0, rotatedCosts, 0, n);
        return IntStream.range(0, n)
                .map(rotate -> {
                    int currentCost = IntStream.of(rotatedCosts).sum();
                    for (int i = 0; i < n; i++) {
                        rotatedCosts[i] = Math.min(rotatedCosts[i], nums[(i + rotate + 1) % n]);
                    }
                    return currentCost + rotate * x;
                })
                .min()
                .orElse(Integer.MAX_VALUE);
    }
}

解释

方法:

该题解运用了单调栈与差分数组的组合技术来寻找最小化收集所有类型巧克力的成本。首先,题解初始化了一个单调栈来存储三元组,每个三元组包含当前巧克力的成本、原始索引和栈中能够影响到的最远索引。接着,使用差分数组dif来跟踪成本变化,每次将最小的成本巧克力对应的成本加到差分数组中,并在必要时调整以保持栈的单调性。最后,通过两次累加差分数组来计算每种操作下的总成本,并找出最小成本。在这个过程中,算法通过从最小成本的巧克力开始,逐步调整和计算操作后的成本,以求得最优解。

时间复杂度:

O(n)

空间复杂度:

O(n)

代码细节讲解

🦆
题解中提到使用单调栈与差分数组组合技术,这种方法在解决问题时具体是如何应用的?
在这个题解中,单调栈与差分数组组合技术被用于优化和简化对成本的计算。单调栈用于维护一个单调递增的成本序列,这样可以保证任何时候栈顶的巧克力都是具有最小成本的。这种结构帮助我们追踪成本最小的巧克力,并及时更新受这些成本影响的范围。差分数组则用于记录成本的增减变化。当我们在单调栈中添加或移除巧克力时,会在差分数组相应的位置记录成本的增加或减少,从而允许我们快速计算任何点的累积成本变化。最终通过累积差分数组来获取每种操作下的总成本,并从中找出最小值。
🦆
在单调栈使用过程中,为什么需要保持栈的单调性,这种单调性具体是指什么?
在单调栈的使用中,保持栈的单调性指的是栈内元素需要按照一定的顺序排列,这里是保持成本的单调递增。这种单调性的保持是为了确保任何时刻我们都能快速访问到当前成本最小的巧克力。当新的巧克力成本低于栈顶巧克力成本时,栈顶巧克力将不再有机会成为最小成本,因此需要被移出栈。这样可以避免不必要的重复计算和复杂的成本管理,同时简化了成本的更新和计算过程。
🦆
为什么需要从数组中最小成本的巧克力开始进行操作?这种策略是基于什么考虑?
从最小成本的巧克力开始操作是基于成本最小化的策略。这样做可以确保我们在处理各种操作时,始终围绕成本最低的点进行优化。通过从最低成本开始,可以最大化利用巧克力的成本效益,因为这将是影响总成本的关键因素。此外,从成本最低点开始计算,使得我们的操作可以尽可能少地增加额外成本,从而在追求最小总成本的过程中保持效率和精确度。

相关问题