You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将数组最大点积问题的自上而下DP转换为自下而上DP?

问题描述

给定两个正整数数组a和b,大小分别为n和m(n≥m),任务是通过在第二个数组中插入零(不得打乱元素顺序)来最大化点积。
数组a和b的点积定义为:a[0]*b[0] + a[1]*b[1] + … + a[n-1]*b[n-1]。

我已经写出了如下自上而下的DP(动态规划)解决方案,运行正常,但想不出对应的迭代(自下而上)实现方式:

public int recurse(int a[], int b[],int aInd, int bInd, int zeroCount,int dp[][]){
        if(bInd>=b.length || aInd>=a.length)
            return 0;
            
       if(dp[aInd][bInd]!=-1)
         return dp[aInd][bInd];
           
       if(zeroCount==0){
            return dp[aInd][bInd]=a[aInd]*b[bInd]+recurse(a,b,aInd+1,bInd+1,0,dp);
        }
        
        
         int makeZero=recurse(a,b,aInd+1,bInd,zeroCount-1,dp);
         int noZero=a[aInd]*b[bInd]+recurse(a,b,aInd+1,bInd+1,zeroCount,dp);
           
         return dp[aInd][bInd]=Math.max(makeZero,noZero);
    }
自下而上迭代DP实现

首先明确:需要插入的零的总数是zeroCount = n - m,因为最终b要被补成n个元素才能和a计算点积。

自下而上的核心是从递归的终止条件反向填充DP表——递归是从aInd=0、bInd=0开始往前算,迭代则从a的最后一个元素、b的最后一个元素开始,逐步往回填充。

对应的迭代代码如下:

public int maxDotProduct(int[] a, int[] b) {
    int n = a.length;
    int m = b.length;
    int zeroCount = n - m;

    // dp[i][j] 表示处理a的第i个元素(a[i])及之后、b的第j个元素(b[j])及之后时,能得到的最大点积
    int[][] dp = new int[n+1][m+1];

    // 边界初始化:当b的所有元素都处理完(j=m),剩下的a元素只能和零相乘,贡献为0
    for (int i = 0; i <= n; i++) {
        dp[i][m] = 0;
    }
    // 边界初始化:当a的所有元素都处理完(i=n),没有元素可计算,贡献为0
    for (int j = 0; j <= m; j++) {
        dp[n][j] = 0;
    }

    // 从后往前遍历填充dp表
    for (int i = n-1; i >= 0; i--) {
        for (int j = m-1; j >= 0; j--) {
            // 剩余可插入的零数:a还剩n-i个元素,b还剩m-j个元素,差值就是还能插的零数
            int remainingZeros = (n - i) - (m - j);
            if (remainingZeros <= 0) {
                // 没零可插了,必须把当前a[i]和b[j]匹配
                dp[i][j] = a[i] * b[j] + dp[i+1][j+1];
            } else {
                // 两种选择:给a[i]插零(不使用b[j],处理下一个a元素);匹配b[j](同时处理下一个a和b元素)
                int chooseZero = dp[i+1][j];
                int chooseMatch = a[i] * b[j] + dp[i+1][j+1];
                dp[i][j] = Math.max(chooseZero, chooseMatch);
            }
        }
    }

    return dp[0][0];
}
思路说明
  1. DP表定义:dp[i][j]代表处理到a[i]和b[j]时,从当前位置到数组末尾能获得的最大点积。
  2. 边界条件:
    • 当j == m(b的元素全部用完),剩下的a元素只能和插入的零相乘,所以这部分贡献为0。
    • 当i == n(a的元素全部处理完),没有元素可以继续计算,贡献为0。
  3. 状态转移:
    • 计算剩余可插入的零数:用a剩余元素数减去b剩余元素数,得到还能插入的零的数量。
    • 如果没有剩余零,只能将a[i]和b[j]相乘,再加上后续位置的最大点积。
    • 如果还有零可以插,取两种选择的最大值:要么给当前a[i]配零(跳过b[j],处理下一个a元素),要么将a[i]和b[j]匹配,同时处理下一组元素。

内容的提问来源于stack exchange,提问作者Random Dude

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 06:05:19