【Leetcode】打气球的最大分数 (暴力递归+动态规划)

题目

给定一个数组arr,代表一排有分数的气球。没打爆一个气球都能获得分数,假设打爆气球的分数为X,获得分数的规则如下:

  1. 如果被打爆气球的左边有没有被打爆的气球,找到离被打爆气球最近的气球,假设分数为L;如果被打爆气球的右边有没被打爆的气球,找到离被打爆气球最近的气球,假设位数为R,那么获得分数为LRX。
  2. 如果被打爆气球的左边有没有被打爆的气球,找到离被打爆气球最近的气球,假设分数为L;右边没有没被打爆的气球,那么获得分为为L*R。
  3. 如果被打爆气球左边没有没被打爆的气球,如果被打爆气球的右边有没被打爆的气球,找到离被打爆气球最近的气球,假设位数为R,那么获得分数为R*X。

目标是打爆所有的气球,获得每次被打爆的分数。通过选择不同的顺序,可以得到不同的总分,求能获得的最大分数。

分析

这也是一道能通过爆搜递归然后进行动态规划优化的模板题。复习 换钱的方法数

下面分别总结爆搜和动态规划

解法1 暴力递归

可以分为以下几种情况:

假设要打爆arr[L…R]范围的气球,并假设arr[L-1]和arr[R+1]的气球还没被打爆,那么获取最大的分的函数为process(L,R)

  1. 如果arr[L]最后被打爆,那么递归为

    process(L+1,R) + arr[L-1]*arr[L]*arr[R+1]

  2. 如果arr[R]最后被打爆,那么递归为

    process(L,R-1) + arr[L-1]*arr[R]*arr[R+1]

  3. 如果arr[i]最后被打爆,那么递归为

    process(L,i-1) + process(i+1,R) + arr[L-1]*arr[i]*arr[R+1]

有了递归方程,那么递归很容易写出

// 暴力递归
int process(int arr[], int L ,int R){
    if(L==R){
        return arr[L-1]*arr[L]*arr[R+1];
    }

    int maxValue = max(
            arr[L-1]*arr[L]*arr[R+1]+process(arr, L+1,R),
            arr[L-1]*arr[R]*arr[R+1]*process(arr, L,R-1)
            );
    for(int i=L+1;i<=R-1;i++){
        maxValue = max(
                maxValue,
                arr[L-1]*arr[i]*arr[R+1]+process(arr, L , i-1)+process(arr,i+1, R)
                );
    }
    return maxValue;
}

在写正式函数的过程,arr可以用一个辅助数组,arr[0]=1,arr[N+1]=1就可以不用考虑边界问题

解法2 动态规划优化

按照暴力递归优化为动态规划的套路:

  1. 首先判断无后效性,可变参数L和R确定了以后,那么返回值就确定了(无后效性)
  2. 然后将L和R作为横纵坐标组成一张表,这种表包括了所有的返回值。
// 动态规划题解
int processDP(int arr[], int length){

    int N = length;
    int help[length+2];
    memset(help,sizeof(help),1);
    for(int i=0;i<N;i++){
        help[i+1] = arr[i];
    }
    int dp[length+1][length+1];
    memset(dp, sizeof(dp),0);
    for(int i=1;i<=N;i++){
        dp[i][i] = help[i]*help[i];
    }
    for(int L=N;L>=1;L++){
        for(int R=L+1;R<=N;R--){
            int finalL = help[L-1]*help[R]*help[L]+ dp[L+1][R];
            int finalR = help[L-1]*help[R+1]*help[R]+ dp[L][R-1];
            dp[L][R] = max(finalL,finalR);
            for(int i=L+1;i<=R;i++){
                dp[L][R] = max(dp[L][R],dp[L][i-1]+dp[i+1][R]+help[L-1]*help[i]*help[R+1]);
            }
        }
    }
    return dp[1][N];
}

总结

review

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值