面试翻车之——股票专题(贪心+状态机dp)
1.1054. 股票买卖 - AcWing题库(贪心)
题意:
只能交易一次
,求最大利润
题解:
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 100010;
int a[N];
int n;
int main()
{
cin>>n;
int minv = 0x3f3f3f3f,res = 0;
for (int i = 0; i < n; i ++ )cin>>a[i];
for (int i = 0; i < n; i ++ ){
if(a[i]<=minv){
//如果比当前最小值还小,说明不能交易,并更新最小值
minv = a[i];
}else{
//如果可以交易,就尝试交易,并与之前保存的最大值比较,保留最大值
res = max(res,a[i]-minv);
}
}
cout << res;
}
2.1055. 股票买卖 II - AcWing题库
题意:
可以交易多次
,求最大利润
题解:
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 100010;
int a[N];
int n;
int main()
{
cin>>n;
int minv = 0x3f3f3f3f, p = 0,res = 0;
for (int i = 0; i < n; i ++ )cin>>a[i];
for (int i = 0; i < n; i ++ ){
if(a[i]<=minv){
//如果比当前最小值还小,说明不能交易
minv = a[i];
}else{
//如果大于当前最小值,就一定要交易,更新最小值为当前数
res+=(a[i]-minv);
minv = a[i];
}
}
cout << res;
}
3.1056. 股票买卖 III - AcWing题库
题意:
可以交易2次
,求最大利润
题解:
#include<bits/stdc++.h>
using namespace std;
const int N = 100010;
int n;
//dp[i][0]存第一次交易的最大收益
//dp[i][1]存第二次交易的最大收益
int w[N],dp[N][2];
int main()
{
cin >> n;
//两次交易没有交集,可以分开看
//只需要分别存下第一次交易在第i天卖出,和第二次交易在第i天买入的最大收益;
//枚举第二次交易的起始日期,求出最值
for (int i = 0; i < n; i ++ )cin>>w[i];
int minv = w[0];
//对于第一次卖出日期值当下的,所以要存前缀中的最小买入值
for (int i = 1; i < n; i ++ ){
dp[i][0] = max(dp[i-1][0],w[i]-minv);
minv = min(minv,w[i]);
}
//对于第二次买入日期值当下的,所以要存后缀缀中的最大卖出值
int maxv = w[n-1];
for (int i = n-1;i>0;i--){
dp[i][1] = max(dp[i-1][1],maxv-w[i]);
maxv = max(w[i],maxv);
}
//枚举买入日期
int res = 0;
for(int i = 1;i<n;i++){
res = max(res,dp[i][0]+dp[i+1][1]);
}
cout << res;
}
4.1057. 股票买卖 IV - AcWing题库
题意:
可以交易最多k次
,求最大利润
题解:
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 100010,M = 105;
int w[N];
//表示进行了前i次交易,已经交易了k次,手里有或没有股票
int dp[N][M][2];
int main()
{
int n,m;
cin >> n>>m;
memset(dp,-0x3f,sizeof dp);
for (int i = 0; i <= n; i++) {
dp[i][0][0] = 0;//手中有股票
}
for (int i = 1; i <= n; i ++ )cin>>w[i];
for (int i = 1; i <= n; i ++ ){
for (int j = 1; j <= m; j ++ ){
//因为手中没有股票可能是没买,也可能是没卖出去,不能作为判断一次交易的依据
dp[i][j][0] = max(dp[i-1][j][0],dp[i-1][j][1]+w[i]);
//只有手里有货算作一次交易,所以进行一次买才会消耗掉一次
dp[i][j][1] = max(dp[i-1][j][1],dp[i-1][j-1][0]-w[i]);
}
}
int res = 0;
for (int i = 0; i <= m; i ++ ){
res = max(res,dp[n][i][0]);
}
cout << res;
}
5.309. 最佳买卖股票时机含冷冻期
题意:
可以交易多次交易
,交易一次后冷冻一天
,求最大利润
题解:
class Solution {
public int maxProfit(int[] prices) {
int n = prices.length;
int [][]dp = new int[n+1][3];
//手中有货
dp[0][0] = -0x3f3f3f;
//手中无货1天
dp[0][1] = -0x3f3f3f;
//手中无货大于2天
dp[0][2] = 0;
for(int i = 1; i <=n; i++) {
dp[i][0] = Math.max(dp[i-1][0],dp[i-1][2]-prices[i-1]);
dp[i][1] = (dp[i-1][0]+prices[i-1]);
dp[i][2] = Math.max(dp[i-1][1],dp[i-1][2]);
}
return Math.max(dp[n][1],dp[n][2]);
}
}
6.714. 买卖股票的最佳时机含手续费
题意:
可以交易多次交易
,每一次交易有固定的手续费
,求最大利润
题解:
class Solution {
public int maxProfit(int[] w, int cost) {
int n = w.length;
int[][] dp = new int[n][2];
//第一次买一定是买第一个
dp[0][1] = -w[0];
for (int i = 1; i < n; i ++ ){
//只有卖的时候交费
dp[i][0] = Math.max(dp[i-1][0],dp[i-1][1]+w[i]-cost);
dp[i][1] = Math.max(dp[i-1][1],dp[i-1][0]-w[i]);
}
return dp[n-1][0];
}
}