手写数学公式识别实战:基于ResNet与Transformer的完整方案
2026/8/31 17:36:22
问题描述:
给定整数数组prices表示股票每日价格,整数k表示最多可完成的交易次数(一次“做多”或“做空”平仓算一笔交易)。交易规则支持两种操作:
k笔交易的前提下,返回能获得的最大利润,未进行任何交易时利润为 0。示例:
示例 1:
输入:prices = [3,2,6,5,0,3], k = 2
输出:7
解释:
示例 2:
输入:prices = [1,2,3,4,5], k = 1
输出:4
解释:做多:第1天买入(1),第5天卖出(5),利润4(1笔交易)。
示例 3:
输入:prices = [7,6,4,3,1], k = 2
输出:0
解释:无论做多/做空均无利润,最优选择不交易。
i天的最大利润仅依赖第i-1天的状态,符合动态规划特征。dp[i][j][s]表示第i天、完成j笔交易、状态s时的最大利润,初始值设为极小值(表示不可达),仅第0天基础状态初始化;publicstaticlongmaximumProfit(int[]prices,intk){intn=prices.length;// 三维DP数组:dp[i][j][s]// i:第i天;j:已完成j笔交易;s:0=无持仓,1=做多持仓,2=做空持仓long[][][]dp=newlong[n][k+1][3];// 初始化所有状态为极小值(不可达),避免溢出用Long.MIN_VALUE/2for(inti=0;i<n;i++){for(intj=0;j<=k;j++){dp[i][j][0]=Long.MIN_VALUE/2;dp[i][j][1]=Long.MIN_VALUE/2;dp[i][j][2]=Long.MIN_VALUE/2;}}// 第0天初始状态dp[0][0][0]=0;// 无交易、无持仓,利润0dp[0][0][1]=-prices[0];// 无交易、做多开仓,利润=-股价dp[0][0][2]=prices[0];// 无交易、做空开仓,利润=+股价// 遍历每一天处理状态转移for(inti=1;i<n;i++){for(intj=0;j<=k;j++){// 状态0:无持仓dp[i][j][0]=Math.max(dp[i][j][0],dp[i-1][j][0]);// 前一天无持仓if(j>=1){// 前一天做多持仓,今日平仓(交易次数+1)dp[i][j][0]=Math.max(dp[i][j][0],dp[i-1][j-1][1]+prices[i]);// 前一天做空持仓,今日平仓(交易次数+1)dp[i][j][0]=Math.max(dp[i][j][0],dp[i-1][j-1][2]-prices[i]);}// 状态1:做多持仓dp[i][j][1]=Math.max(dp[i][j][1],dp[i-1][j][1]);// 前一天做多持仓dp[i][j][1]=Math.max(dp[i][j][1],dp[i-1][j][0]-prices[i]);// 今日开多仓// 状态2:做空持仓dp[i][j][2]=Math.max(dp[i][j][2],dp[i-1][j][2]);// 前一天做空持仓dp[i][j][2]=Math.max(dp[i][j][2],dp[i-1][j][0]+prices[i]);// 今日开空仓}}// 最后一天所有交易次数下,无持仓的最大利润longmaxProfit=0;for(intj=0;j<=k;j++){maxProfit=Math.max(maxProfit,dp[n-1][j][0]);}returnmaxProfit;}f[j][s](仅保留交易次数和状态),利用“逆序遍历交易次数”避免状态覆盖,空间复杂度从 O(nk3) 降至 O(k*3);k+2长度的数组规避交易次数边界判断,代码更简洁。classSolution{publiclongmaximumProfit(int[]prices,intk){// 二维数组:f[j][s] 表示完成j-1笔交易、状态s时的最大利润(空间压缩)long[][]f=newlong[k+2][3];// 初始化不可达状态(防止溢出)for(intj=1;j<=k+1;j++){f[j][1]=Long.MIN_VALUE/2;}f[0][0]=Long.MIN_VALUE/2;// 遍历每日价格,逆序处理交易次数(避免覆盖)for(intp:prices){for(intj=k+1;j>0;j--){// 状态0:无持仓,来自做多平仓/做空平仓/无持仓f[j][0]=Math.max(f[j][0],Math.max(f[j][1]+p,f[j][2]-p));// 状态1:做多持仓,来自前序无持仓开仓f[j][1]=Math.max(f[j][1],f[j-1][0]-p);// 状态2:做空持仓,来自前序无持仓开仓f[j][2]=Math.max(f[j][2],f[j-1][0]+p);}}// 最终取完成k笔交易后无持仓的最大利润returnf[k+1][0];}}n天,每天遍历k+1次交易次数,每次处理3种状态,均为常数级操作;n*(k+1)*3,主导空间开销。n天,每天逆序遍历k+1次交易次数,时间效率与原代码一致;(k+2)*3,空间复杂度从线性级降至常数级(相对于n)。本题是“带做空机制的有限次数股票交易”问题,核心是拆分持仓状态+动态规划状态转移,关键在于:
Long.MIN_VALUE/2;