算法分析
初始化:f[0][j][0] = 0
, 其余-INF
,因为在第0
个股票一定是无货的,必定从这个位置开始转移才有效
注意:
这里状态机的过程,对于每个股票,要么就买,要么就卖,不能说是买了然后在同一个点直接卖掉,这样是不符合状态机模型的,因此对于上述转移方程可以会有人提出疑问。
为什么状态转移方程不能是下面代码,即卖的时候才算做了一次交易,原代码是买的时候才算一次交易
f[i][j][0] = max(f[i - 1][j - 1][1] + w[i], f[i - 1][j][0]);
f[i][j][1] = max(f[i - 1][j][0] - w[i], f[i - 1][j][1]);
终究要回归到状态转移的起点,第一支股票只有买,和不买这两个操作,一定不可能是卖和不卖的这两个操作,因此第一支股票如果买入时,必须按照一次交易处理。否则如果第一次股票如果买入时,不按一次交易处理,也就代表着第一支股票卖出才算一次交易,也就代表着在第一支股票卖出之前还买了一支股票,显然是矛盾的。
非状态机解法 LeetCode 188. 买卖股票的最佳时机 IV
时间复杂度 $O(nm)$
空间复杂度 $O(m)$
从$O(nm)$优化到$O(m)$
参考文献
算法提高课
Java 代码(空间优化前,在这里会gg的代码,c++不会)
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
public class Main {
static int N = 100010, M = 110, INF = 0x3f3f3f3f;
static int n, m;
static int[] w = new int[N];
static int[][][] f = new int[N][M][2];
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String[] s1 = br.readLine().split(" ");
n = Integer.parseInt(s1[0]);
m = Integer.parseInt(s1[1]);
String[] s2 = br.readLine().split(" ");
for(int i = 1;i <= n;i ++) w[i] = Integer.parseInt(s2[i - 1]);
for(int i = 0;i <= n;i ++)
for(int j = 0;j <= m;j ++)
Arrays.fill(f[i][j], -INF);
for(int i = 0;i <= n;i ++) f[i][0][0] = 0;
for(int i = 1;i <= n;i ++)
for(int j = 1;j <= m;j ++)
{
f[i][j][0] = Math.max(f[i - 1][j][1] + w[i], f[i - 1][j][0]);
f[i][j][1] = Math.max(f[i - 1][j - 1][0] - w[i], f[i - 1][j][1]);
}
int res = 0;
for(int i = 1;i <= m;i ++) res = Math.max(res, f[n][i][0]);
System.out.println(res);
}
}
Java 代码(空间优化后)
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
public class Main {
static int N = 100010, M = 110, INF = 0x3f3f3f3f;
static int n, m;
static int[] w = new int[N];
static int[][] f = new int[M][2];
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String[] s1 = br.readLine().split(" ");
n = Integer.parseInt(s1[0]);
m = Integer.parseInt(s1[1]);
String[] s2 = br.readLine().split(" ");
for(int i = 1;i <= n;i ++) w[i] = Integer.parseInt(s2[i - 1]);
for(int j = 0;j <= m;j ++)
Arrays.fill(f[j], -INF);
f[0][0] = 0;
for(int i = 1;i <= n;i ++)
for(int j = m;j >= 1;j --)
{
f[j][0] = Math.max(f[j][1] + w[i], f[j][0]);
f[j][1] = Math.max(f[j - 1][0] - w[i], f[j][1]);
}
int res = 0;
for(int i = 1;i <= m;i ++) res = Math.max(res, f[i][0]);
System.out.println(res);
}
}
为啥开头初始化f[0][j][0] = 0,在代码那里是f[i][0][0] = 0了
看了你的一下就懂自己错哪了
感谢感谢!
其实交易次数的说法是有问题的,应该从最后一次去看,如果卖出到买入算一次的话,那最后一次可能处于冷冻态
作者好像是以买入作为一次交易的标志,但是在代码中并没有体现,比如f[i][j][0],如果以作者的想法的话,那么i-1层
的交易次数就应该是j - 1,而不是j了,还是有问题的
题解好清晰
啊?可是我写卖+1,过了啊
但是题目不是说完整的一次买入卖出才算一次交易吗 如果第一次买入就算一次交易 那不就不符合题意了
你可以以买入为一次交易的标志,也可以以卖出为一次交易的标志,都是可以的,但是以卖出为一次交易的时候,那第一天就不能卖出,要在i大于1的时候才可以
终于明白为什么不能卖算一次交易了
hh
解释疑惑太赞了!Orz
hh