Easy
题目描述
给你一个大小为 n 的整数数组 cost。你目前在一列 n + 1 个人(编号从 0 到 n)的末尾位置 n。
你希望在队列中向前移动,但你前面的每个人都会收取特定的费用来交换位置。与第 i 个人交换的成本由 cost[i] 给出。
你可以按以下方式与人们交换位置:
- 如果他们在你前面,你必须支付 cost[i] 与他们交换。
- 如果他们在你后面,他们可以免费与你交换。
返回一个大小为 n 的数组 answer,其中 answer[i] 是到达队列中每个位置 i 的最小总成本。
示例 1:
输入:cost = [5,3,4,1,3,2]
输出:[5,3,3,1,1,1]
解释:
我们可以通过以下方式到达每个位置:
- i = 0:我们可以与第 0 个人交换,成本为 5。
- i = 1:我们可以与第 1 个人交换,成本为 3。
- i = 2:我们可以与第 1 个人交换,成本为 3,然后免费与第 2 个人交换。
- i = 3:我们可以与第 3 个人交换,成本为 1。
- i = 4:我们可以与第 3 个人交换,成本为 1,然后免费与第 4 个人交换。
- i = 5:我们可以与第 3 个人交换,成本为 1,然后免费与第 5 个人交换。
示例 2:
输入:cost = [1,2,4,6,7]
输出:[1,1,1,1,1]
解释:
我们可以与第 0 个人交换,成本为 1,然后免费到达任何位置 i。
约束条件:
- 1 <= n == cost.length <= 100
- 1 <= cost[i] <= 100
解题思路
解题思路
这道题的关键在于理解交换规则:我们只能向前(位置编号减小)移动,且一旦到达某个位置,就可以免费与后面的任何人交换。
核心观察
- 我们从位置 n 开始,想要到达位置 i(i < n)
- 与前面的人交换需要付费,与后面的人交换免费
- 一旦我们到达某个位置 j,就可以免费到达所有位置 k(k > j)
解法分析
贪心策略:对于每个位置 i,我们需要找到从当前位置到位置 i 的最小成本路径。
关键insight:到达位置 i 的最小成本等于从位置 i 到位置 n 的最小前缀成本。换句话说,我们需要找到区间 [i, n-1] 中的最小值。
算法步骤:
- 从右到左维护一个最小值
- 对于每个位置 i,answer[i] 就是从位置 i 到末尾的最小 cost 值
- 这是因为我们可以先移动到成本最低的位置,然后免费到达目标位置
这种方法的正确性在于:一旦我们到达了区间 [i, n-1] 中成本最低的位置,就可以免费移动到位置 i。
代码实现
class Solution {
public:
vector<int> minCosts(vector<int>& cost) {
int n = cost.size();
vector<int> answer(n);
// 从右到左维护最小值
int minCost = cost[n-1];
answer[n-1] = minCost;
for (int i = n - 2; i >= 0; i--) {
minCost = min(minCost, cost[i]);
answer[i] = minCost;
}
return answer;
}
};
class Solution:
def minCosts(self, cost: List[int]) -> List[int]:
n = len(cost)
answer = [0] * n
# 从右到左维护最小值
min_cost = cost[n-1]
answer[n-1] = min_cost
for i in range(n-2, -1, -1):
min_cost = min(min_cost, cost[i])
answer[i] = min_cost
return answer
public class Solution {
public int[] MinCosts(int[] cost) {
int n = cost.Length;
int[] answer = new int[n];
// 从右到左维护最小值
int minCost = cost[n-1];
answer[n-1] = minCost;
for (int i = n - 2; i >= 0; i--) {
minCost = Math.Min(minCost, cost[i]);
answer[i] = minCost;
}
return answer;
}
}
/**
* @param {number[]} cost
* @return {number[]}
*/
var minCosts = function(cost) {
const n = cost.length;
const answer = new Array(n);
// 从右到左维护最小值
let minCost = cost[n-1];
answer[n-1] = minCost;
for (let i = n - 2; i >= 0; i--) {
minCost = Math.min(minCost, cost[i]);
answer[i] = minCost;
}
return answer;
};
复杂度分析
| 复杂度类型 | 值 |
|---|---|
| 时间复杂度 | O(n) |
| 空间复杂度 | O(1) |
说明:
- 时间复杂度:只需要遍历数组一次
- 空间复杂度:除了输出数组外,只使用了常数额外空间