题目描述
商人经营一家店铺,有number
种商品,由于仓库限制每件商品的最大持有数量是item[index]
,每种商品的价格是itemprice[item_index][day]
。
通过对商品的买进和卖出获取利润,请给出商人在days
天内能获取的最大的利润。
注:同一件商品可以反复买进和卖出
输入描述
- 第一行输入商品的数量
number
,比如3
- 第二行输入商品售货天数
days
,比如3
- 第三行输入仓库限制每件商品的最大持有数量是
item[index]
,比如4 5 6
- 后面继续输入
number
行days
列,含义如下:- 第一件商品每天的价格,比如
1 2 3
- 第二件商品每天的价格,比如
4 3 2
- 第三件商品每天的价格,比如
1 5 3
- 第一件商品每天的价格,比如
输出描述
输出商人在这段时间内的最大利润。
示例1
输入
3
3
4 5 6
1 2 3
4 3 2
1 5 2
输出
32
示例2
输入
1
1
1
1
输出
0
思考
商品买卖赚差价,如果第二天价格比当天价格高,那么当天买入第二天卖出一定有收益。如果第三天价格更高,是不是一定要第一天买入然后等到第三天卖出才能获得最大收益?举个例子:某个商品三天的价格表是 [1, 4, 100],如果第一天买入,第三天卖出,那么收益是 100 - 1 = 99。肯定不会选择第二天买入第三天卖出,第二天价格比第一天高容易判断。如果我第一天买入,第二天卖出,然后又在第二天买入,然后在第三天卖出呢?收益是 -1 + 4 - 4 + 100 = 100 -1 = 99,发现和第一天买入第三天卖出一样的结果。两种方式的收益相同,原因是多次买卖的中间买入和卖出操作相互抵消。具体表现为:
- 第二天卖出时收益为 4 - 1 = 3。
- 第二天买入时成本为 4,第三天卖出时收益为 100 - 4 = 96。
- 总收益为 3 + 96 = 99,与单次买卖一致。
因此这题采用贪心策略求解,只要下一天的商品价格比当前价格高就买入,这样最终能获得最大收益。题目与 LeetCode 121.买卖股票的最佳时机类似。
算法过程
- 输入处理:
- 读取商品数量
number
、天数days
。 - 读取每种商品的最大持有数量
items
。 - 读取每种商品每天的价格
itemprices
。
- 读取商品数量
- 计算每种商品的最大利润:
- 对于每种商品,遍历每一天的价格。
- 如果后一天的价格比前一天高,计算差价并累加到该商品的利润中。
- 计算总利润:
- 将每种商品的利润乘以最大持有数量,累加到总利润中。
- 输出总利润。
复杂度分析
- 时间复杂度:O(n × days),其中n是商品数量,days是天数。需要遍历每种商品的每天价格。
- 空间复杂度:O(n × days),存储价格矩阵。
参考代码
function solution() {
const n = Number(readline());
const days = Number(readline());
const items = readline().split(' ').map(Number);
const itemprices = [];
for (let i = 0; i < days; i++) {
itemprices[i] = readline().split(' ').map(Number);
}
let totalProfit = 0;
for (let i = 0; i < n; i++) { // 遍历每件商品
// 每件商品在days天内买卖能获得的最大利润
let maxProfit = 0;
for (let j = 0; j < days-1; j++) {
// 贪心策略:每件商品只要第二天价格高于当天价格就能买入赚差价
if (itemprices[i][j] < itemprices[i][j+1]) {
maxProfit += itemprices[i][j+1] - itemprices[i][j];
}
}
totalProfit += maxProfit * items[i];
}
console.log(totalProfit);
}
const cases = [
` 3
3
4 5 6
1 2 3
4 3 2
1 5 2`,
`1
1
1
1`,
];
let caseIndex = 0;
let lineIndex = 0;
const readline = (function () {
let lines = [];
return function () {
if (lineIndex === 0) {
lines = cases[caseIndex]
.trim()
.split("\n")
.map((line) => line.trim());
}
return lines[lineIndex++];
};
})();
cases.forEach((_, i) => {
caseIndex = i;
lineIndex = 0;
solution();
});