LeetCode 312.戳气球

LeetCode 312.戳气球

说明:
你可以假设 nums[-1] = nums[n] = 1,但注意它们不是真实存在的所以并不能被戳破。0 ≤ n ≤ 500, 0 ≤ nums[i] ≤ 100

动态规划

确定状态:
分析: 所有N个气球被扎破

  • 最后一步: 一定有一个最后一个被扎破的气球编号为i。扎破i时,左边是气球0(nums[-1]),右边是气球n+1(nums[n]),获得金币1*a[i]*1
  • 此时气球1~i-1以及i+1~n都已经被扎破,并且已经获得对应的金币。
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  • 子问题:要求1~N号气球最多获得的金币数:需要知道1~i-1号最多获得的金币数i+1~N号气球最多获得的金币数
  • 状态:设f[i][j]为扎破i+1~j-1号气球,最多获得的金币数。(ij不能扎破)

转移方程:
f [ i ] [ j ] = m a x i < k < j { f [ i ] [ k ] + f [ k ] [ j ] + a [ i ] ∗ a [ k ] ∗ a [ j ] } f[i][j]=max_{i<k<j}\{f[i][k]+f[k][j]+a[i]*a[k]*a[j]\} f[i][j]=maxi<k<j{f[i][k]+f[k][j]+a[i]a[k]a[j]}
f[i][j]:扎破i+1~j-1号气球最多获得的金币数。
f[i][k]:扎破i+1~k-1号气球最多获得的金币数。
f[k][j]:扎破k+1~j-1号气球最多获得的金币数。
a[i]*a[k]*a[j]:最后扎破k号气球获得的金币数。

初始条件:
f[0][1]=f[1][2]=...=f[N][N+1]=0
按照区间从小到大的顺序计算

class Solution {
    public int maxCoins(int[] nums) {
        int n=nums.length;
        if(n==0)
            return 0;
          //原数组中nums[-1]和nums[n]不合法,拷贝到新数组A中。
        int []A=new int[n+2];
        int i,j,k,len;
        A[0]=A[n+1]=1;
        for(i=0;i<n;i++)
        {
            A[i+1]=nums[i];
        }
        n+=2;
        int [][]f=new int[n][n];
        //区间长度为2时
        for(i=0;i<n-1;i++)
        {
            f[i][i+1]=0;
        }
        //从区间长度为3开始遍历
        for(len=3;len<=n;len++)
        {
            for(i=0;i<=n-len;i++)
            {
                j=i+len-1;
                f[i][j]=Integer.MIN_VALUE;
                for(k=i+1;k<j;k++)
                {
                    f[i][j]=Math.max(f[i][j],f[i][k]+f[k][j]+A[i]*A[k]*A[j]);
                }
            }
        }
        return f[0][n-1];
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值