题目1:
指路:
方法一:贪心
思路与分析:
对于买卖股票的操作,只有买入和卖出两种操作,而利益最大化在理想状态下无非是贪心买卖:买入的价钱最小同时卖出的价钱最大。那么我们通过遍历数组元素以遍历位置i为界限前为买入后为卖出(先买入才能卖出),维护i以前最小的买入值和i以后的最大卖出值使利润差值最大。那么这里我们定义一个最小买入值并初始化为INT_MAX使其能有效赋值。
代码:
class Solution {
public:
int maxProfit(vector<int>& prices) {
int low = INT_MAX; // 最小值
int ans = 0; // 最后答案
for (int i = 0; i < prices.size(); i++) {
low = min(low, prices[i]); // 维护最小的买入值
ans = max(prices[i] - low, ans); // 维护最大的卖出值
}
return ans;
}
};
方法二:动态规划
思路与分析:
在这里我们可以尝试用动态规划解题,那么在这里设给出的数组peices大小为n,n的含义为有n次可供操作,其中每次有买入和卖出两种状态。是以我们定义一个二维数组dp[i][j],其中i为第i+1(i/j从0开始计数)天,j为第j+1个状态,j的取值为0或1(0为已买入未卖出,1为已买入已卖出)。其含义为第i+1天第j+1个状态下的最大利润。尝试对其进行初始化。其中dp[0][0]的含义为第一天第1个状态的最大利润,此时已经买入还未卖出,因此dp[0][0]=-prices[0];而dp[0][1]的含义为第一天第2个状态的最大利润,此时已经买入并且已经卖出,因此dp[0][1]=0。再看状态转移方程,在当天的买入后利润最大值是前一天卖出后的利润与今天买入后的较大值;而当天卖出后的利润最大值是前一天卖出后的利润与(前一天买入后的利润和当天卖出)的较大值。其中遍历方向毋庸置疑是从前往后。最后返回最后一天卖出后的利润。
代码:
class Solution {
public:
int maxProfit(vector<int>& prices) {
int n = prices.size();
if (n == 0) return 0;
vector<vector<int>> dp(n, vector<int> (2));
dp[0][0] = -prices[0]; // [0][0]第二个0假设表示已买入未卖出
dp[0][1] = 0; // [0][1]第二个1假设表示未买入已卖出
for (int i = 1; i < n; i++) { // 从第二个元素开始卖出
dp[i][0] = max(dp[i - 1][0], -prices[i]); // 已买入未卖出
dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] + prices[i]); // 未买入已卖出
}
return dp[n - 1][1];
}
};
题目2:
指路:
. - 力扣(LeetCode)122 买卖股票的最佳时机Ⅱ
方法一:贪心
思路与分析:
在这里我们不难看出这支股票可以多次买卖,甚至买入当天就能卖出,但是必须在卖出后才能买入(不能同时持股多个)。其中利润相加即可得到最大累计利润。其实只要当利润是正数时就能得到显著利润。那么我们直接让当天的股价减去前一天的股价,如果是负数则不处理,如果是正数则让利润加之。
代码:
class Solution {
public:
int maxProfit(vector<int>& prices) {
int n = prices.size();
int ans = 0;
for (int i = 1; i < n; i++) {
ans += max(0, prices[i] - prices[i - 1]);
}
return ans;
}
};
方法二:动态规划
思路与分析:
如果买入和卖出的概念不好理解,那么我们用股票的持有与否作为判断条件。当天持股的含义为:至少是前一天持股直到当天依旧未卖出,或者是至少是前一天不持股直到当天买入才开始持股。那么同样,当天不持股的含义为:至少前一天不持股(已卖出)或者是当天卖出才开始不持股。延续前面的二位dp数组,其中i与j以及dp数组的含义相同,根据我们在这里提到的持股与否的定义,我们可以找到当天持股与否的利润较大值。
代码:
class Solution {
public:
int maxProfit(vector<int>& prices) {
int n = prices.size();
vector<vector<int>> dp(n, vector<int>(2));
dp[0][0] = -prices[0]; // 买入未卖出--持股
dp[0][1] = 0; // 买入已卖出--未持股
for (int i = 1; i < n; i++) {
dp[i][0] = max(dp[i - 1][1] - prices[i], dp[i - 1][0]); // 当天买入VS前一天卖出
dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] + prices[i]); // 前一天卖出VS前一天买入当天卖出
}
return dp[n - 1][1];
}
};
股票问题有Ⅰ、Ⅱ、Ⅲ、Ⅳ。建议多次练习。