大家好,我是晴天学长, 一个找状态的经典题,需要的小伙伴可以关注支持一下哦!后续会继续更新的。💪💪💪
1) .买卖股票的最好时机(三)
假设你有一个数组prices,长度为n,其中prices[i]是某只股票在第i天的价格,请根据这个价格数组,返回买卖股票能获得的最大收益
1. 你最多可以对该股票有两笔交易操作,一笔交易代表着一次买入与一次卖出,但是再次购买前必须卖出之前的股票
2. 如果不能获取收益,请返回0
3. 假设买入卖出均无手续费
要求: 空间复杂度 O(n)O(n),时间复杂度 O(n)O(n)
进阶:空间复杂度 O(1)O(1),时间复杂度 O(n)O(n)
输入描述:
第一行输入一个正整数 n ,表示数组 prices 的长度
第一行输入 n 个正整数,表示数组 prices 的所有元素的值
输出描述:
输出最大收益
示例1
输入:
6
8 9 3 5 1 3
输出:
4
复制
说明:
第三天(股票价格=3)买进,第四天(股票价格=5)卖出,收益为2
第五天(股票价格=1)买进,第六天(股票价格=3)卖出,收益为2
总收益为4.
示例2
输入:
4
9 8 4 1
输出:
0
示例3
输入:
5
1 2 8 3 8
输出:
12
说明:
第一笔股票交易在第一天买进,第三天卖出;第二笔股票交易在第四天买进,第五天卖出;总收益为12。
因最多只可以同时持有一只股票,所以不能在第一天进行第一笔股票交易的买进操作,又在第二天进行第二笔股票交易的买进操作(此时第一笔股票交易还没卖出),最后两笔股票交易同时在第三天卖出,也即以上操作不满足题目要求。
2) .算法思路
买卖股票的最好时机(三)
最大收益
dp[i][j] 为第i天股票买卖状态的最大收益
0.不操作
1.第一次买入buy1
2第一次卖出sale1
3第二次买入buy2
4第二次卖出sale2
3)算法步骤
1.读取输入值:
(1)读取第一行,包含一个整数 n,表示股票价格的天数。
(2)读取第二行,包含 n 个以空格分隔的整数,表示每天的股票价格。
2.创建一个大小为 n x 5 的二维数组 dp,用于存储动态规划的状态。每行代表一天,每列代表一个特定的状态:
(1)dp[i][0] 表示第 i 天没有进行任何交易时的最大利润。
(2)dp[i][1] 表示第 i 天进行第一次买入后的最大利润。
(3)dp[i][2] 表示第 i 天进行第一次卖出后的最大利润。
(4)dp[i][3] 表示第 i 天进行第二次买入后的最大利润。
(5)dp[i][4] 表示第 i 天进行第二次卖出后的最大利润。
3.初始化初始状态:
(1)将 dp[0][1] 设置为第一天股票价格的负值,表示在第 0 天买入。
(2)将 dp[0][3] 设置为第一天股票价格的负值,表示在第 0 天再次买入。
4.从第二天(i = 1)开始迭代到最后一天(n - 1):
(1)将 dp[i][0] 设置为 0,因为这一天没有进行任何交易。
(2)更新 dp[i][1],取 dp[i - 1][1] 和 dp[i - 1][0] - nums[i] 中的最大值,表示不买或在这一天买入。
(3)更新 dp[i][2],取 dp[i - 1][2] 和 dp[i - 1][1] + nums[i] 中的最大值,表示不卖或在这一天卖出。
(4)更新 dp[i][3],取 dp[i - 1][3] 和 dp[i - 1][2] - nums[i] 中的最大值,表示不买或在这一天再次买入。
(5)更新 dp[i][4],取 dp[i - 1][4] 和 dp[i - 1][3] + nums[i] 中的最大值,表示不卖或在这一天再次卖出。
(6)更新 max 变量,取 max 和 dp[i][4] 中的最大值。
5.检查最大利润 max 是否大于 0:
(1)如果是,打印 max 的值。
(2)否则,打印 0。
4). 代码实例
import java.io.*;
public class Main {
static BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
static PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
static String[] lines;
public static void main(String[] args) throws IOException {
lines = in.readLine().split(" ");
int n = Integer.parseInt(lines[0]);
int[] nums = new int[n];
lines = in.readLine().split(" ");
for (int i = 0; i < n; i++) {
nums[i] = Integer.parseInt(lines[i]);
}
int[][] dp = new int[n][5];
dp[0][1] = -nums[0];
//第二次买入也算进去,只不过把第一次买入当成0了
dp[0][3] = -nums[0];
int max = 0;
for (int i = 1; i < n; i++) {
dp[i][0] = 0;
dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] - nums[i]);
dp[i][2] = Math.max(dp[i - 1][2], dp[i - 1][1] + nums[i]);
dp[i][3] = Math.max(dp[i - 1][3], dp[i - 1][2] - nums[i]);
dp[i][4] = Math.max(dp[i - 1][4], dp[i - 1][3] + nums[i]);
max = Math.max(max, dp[i][4]);
}
if (max > 0) {
out.println(max);
} else out.println(0);
out.flush();
out.close();
}
}
5). 总结
- 动规的状态选择很重要,当一个复杂的时候,选择另一个状态为切入点。
试题链接: