大家好,我是听雨,是一名跨考计算机专业的研一学生。为提高编程的水平,计划每天刷编程题目。由于我是算法小白,所以开始只能从简单题开始写贴,请大家多多包涵,希望和大家一起进步
题目
今天的第二题为 力扣121. 买卖股票的最佳时机
解题思路
一 . 动态规划
这道题第一次看的时候觉得很简单,准备用左右两个指针来对数组进行交叉遍历,很可惜,200多个测试数据总是有几个数据是错误的,这让我不得不换一种思路。面对这样的题目,动态规划无疑是一种好的想法,于是开始寻找最优子序列的递归关系式。设置dp数组为存放最优子序列的数组, dp[i] 为第 i 天结束的最大利润值。可以想到 dp[i + 1] 是与 dp[i] 和 **prices[i + 1]**是有关系的。最大利润值是通过后天的最大值减去前面几天的最小值来得到的,因此可以想到用一个变量来存放前几天的最小值,并不停迭代这个值。这一点只要在遍历数组的时候就可以做到,记为
m
i
n
min
min。那么只需要比较 dp[i] 和 prices[i] - min大小就可以得到 **dp[i + 1]**的取值。递推关系式如下:
d
p
[
i
+
1
]
=
m
a
x
{
d
p
[
i
]
,
p
r
i
c
e
s
[
i
]
−
m
i
n
}
dp[i + 1] = max \{ dp[i],prices[i]-min \}
dp[i+1]=max{dp[i],prices[i]−min}
初始值
d
p
[
0
]
=
0
dp[0]=0
dp[0]=0
代码如下:
class Solution {
public int maxProfit(int[] prices) {
int len = prices.length;
int min = prices[0];
int[] dp = new int[len];
int res = 0;
dp[0] = 0;
for (int i = 1; i < len; i++) {
min = min < prices[i] ? min : prices[i];
dp[i] = Math.max(dp[i - 1], prices[i] - min);
res = res > dp[i] ? res : dp[i];
}
return res;
}
}
结果如下:
这样跑出来的结果为似乎拿时间换空间了。
二. 贪心算法
速度更快的算法,我从题解中看到有大佬用贪心算法来写,于是我复现了一下。若第 1 天价格低于第 2 天价格,即第 1 天成本更低,那么我们一定不会选择在第 2 天买入。进一步的,若在前 i 天选择买入,若想达到最高利润,则一定选择价格最低的交易日买入。考虑根据此贪心思想,遍历价格列表 prices 并执行两步:
1.更新前 i 天的最低价格,即最低买入成本 ;
2.更新前 i 天的最高利润 ,即选择前i - 1天最高利润和第 i 天卖出的最高利润 中的最大值
如下公式所示:
c
o
s
t
=
{
m
i
n
{
c
o
s
t
,
p
r
i
c
e
s
[
i
]
}
p
r
o
f
i
t
=
m
a
x
{
p
r
o
f
i
t
,
p
r
i
c
e
s
[
i
]
−
c
o
s
t
}
(
第
i
天
)
cost = \begin{cases} min\{ cost,prices[i]\} \\ profit = max\{profit,prices[i] - cost\} \end{cases}\tag{第$i$天}
cost={min{cost,prices[i]}profit=max{profit,prices[i]−cost}(第i天)
初始的 c o s t cost cost值设置为尽量大, p r o f i t profit profit设置为0.
代码如下:
class Solution {
public int maxProfit(int[] prices) {
int cost = 100000; //成本
int res = 0; //利润
for(int i = 0; i < prices.length; i ++){
//更新最小成本
cost = Math.min(prices[i],cost);
//更新最大利润
res = Math.max(res,prices[i] - cost );
}
return res;
}
结果如下:
总结
这道题中学到了贪心思想的构建,尽管代码量很少,但真的对我来说没学过几乎没办法想出来。日后还需继续掌握啊!