题目
给定一个整型数组,它的第i个元素是一支给定股票第i天的价格。如果最多只允许完成一笔交易(即买入和卖出一支股票一次),设计一个算法来计算你所能获取的最大利润。注意:你不能在买入股票前卖出股票。
示例 1:
输入: [7, 1, 5, 3, 6, 4]
输出: 5
解释: 在第2天(股票价格=1)的时候买入,在第5天(股票价格=6)的时候卖出,最大利润为6-1=5。
注意:利润不能是7-1=6, 因为卖出价格需要大于买入价格;同时,不能在买入前卖出股票。
示例 2:
输入: [7, 6, 4, 3, 1]
输出: 0
解释: 在这种情况下, 没有交易完成, 所以最大利润为0。
解析
这道题比较贴合实际,主要考察应聘者对暴力法、贪心算法、动态规划算法等的理解和掌握。
首先,我们使用暴力法来求解本题。暴力法需要遍历数组两遍,故时间复杂度为O(n^2)。我们可以用变量i表示买入股票的索引,用变量j表示卖出股票的索引,那么prices[j] - prices[i]就是股票收益,我们找出最大的即可。具体的实现,可以参考下面的示例代码。
use std::cmp::max;
fn get_max_profit(prices: &Vec<i32>) -> i32 {
let mut max_profit = 0;
for i in 0..prices.len() {
for j in i + 1..prices.len() {
max_profit = max(max_profit, prices[j] - prices[i]);
}
}
max_profit.max(0)
}
fn main() {
let prices = vec![7, 1, 5, 3, 6, 4];
let result = get_max_profit(&prices);
println!("{}", result);
}
接下来,看看如何使用贪心算法求解本题。贪心算法的思路为:遍历数组一遍,每次计算出当前的股票总收益,如果比最大收益大,则更新最大收益。贪心算法的时间复杂度为O(n),具体的实现,可以参考下面的示例代码。
fn get_max_profit(prices: &[i32]) -> i32 {
let profits: Vec<i32> = prices
.windows(2)
.map(|window| window[1] - window[0])
.collect();
let mut max_profit = -1;
let mut current_sum = -1;
for &profit in &profits {
if current_sum > 0 {
current_sum += profit;
} else {
current_sum = profit;
}
if current_sum > max_profit {
max_profit = current_sum;
}
}
max_profit.max(0)
}
fn main() {
let prices = vec![7, 1, 5, 3, 6, 4];
let result = get_max_profit(&prices);
println!("{}", result);
}
最后,我们使用动态规划算法来求解本题。动态规划一般分为一维、二维,对应形式为:dp(i)、dp(i)(j)。使用动态规划算法的处理步骤如下。
1、明确dp(i)应该表示什么(二维情况为dp(i)(j))。
2、根据dp(i)和dp(i-1)的关系得出状态转移方程。
3、确定初始条件,一般为:dp(0)。
由于本题最多只允许完成一笔交易(即买入和卖出一支股票一次),属于一维动态规划。我们用dp[i]表示前i天的最大利润,因为始终要使利润最大化,则:dp[i] = max(dp[i-1], prices[i] - minprice)。动态规划算法的时间复杂度为O(n),具体的实现,可以参考下面的示例代码。
fn get_max_profit(prices: &[i32]) -> i32 {
let count = prices.len();
if count <= 1 {
return 0;
}
let mut vct_dp = vec![0; count];
let mut min_price = prices[0];
for i in 1..count {
min_price = min_price.min(prices[i]);
vct_dp[i] = vct_dp[i - 1].max(prices[i] - min_price);
}
vct_dp[count - 1]
}
fn main() {
let vct_price = vec![7, 1, 5, 3, 6, 4];
let result = get_max_profit(&vct_price);
println!("{}", result);
}
总结
通过这道题,我们学习了暴力法、贪心算法、动态规划算法在解决买卖股票问题时的解题思路。但是,你真的理解透彻了吗?下面是一道关于买卖股票问题的扩展题,快来试一下吧!
给定一个整型数组,它的第i个元素是一支给定股票第i天的价格。如果不限制交易次数,设计一个算法来计算你所能获取的最大利润。注意:你不能同时参与多笔交易(你必须在再次购买前,出售掉之前所有的股票,且不能在卖出股票后的同一天再买入股票)。
示例 1:
输入: [7, 1, 5, 3, 6, 4]
输出: 7
解释: 在第2天(股票价格=1)的时候买入,在第3天(股票价格=5)的时候卖出, 这笔交易所能获得利润为5-1=4 。随后,在第4天(股票价格=3)的时候买入,在第5天(股票价格=6)的时候卖出, 这笔交易所能获得利润为6-3= 3。
示例2:
输入: [1, 2, 3, 4, 5]
输出: 4
解释: 在第1天(股票价格=1)的时候买入,在第5天(股票价格=5)的时候卖出, 这笔交易所能获得利润为5-1=4 。
注意:你不能在第1天和第2天接连购买股票,之后再将它们卖出。因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。