列表

详情


312. 戳气球

n 个气球,编号为0n - 1,每个气球上都标有一个数字,这些数字存在数组 nums 中。

现在要求你戳破所有的气球。戳破第 i 个气球,你可以获得 nums[i - 1] * nums[i] * nums[i + 1] 枚硬币。 这里的 i - 1i + 1 代表和 i 相邻的两个气球的序号。如果 i - 1i + 1 超出了数组的边界,那么就当它是一个数字为 1 的气球。

求所能获得硬币的最大数量。

 

示例 1:
输入:nums = [3,1,5,8]
输出:167
解释:
nums = [3,1,5,8] --> [3,5,8] --> [3,8] --> [8] --> []
coins =  3*1*5    +   3*5*8   +  1*3*8  + 1*8*1 = 167

示例 2:

输入:nums = [1,5]
输出:10

 

提示:

相似题目

合并石头的最低成本

原站题解

去查看

上次编辑到这里,代码来自缓存 点击恢复默认模板
class Solution { public: int maxCoins(vector<int>& nums) { } };

java 解法, 执行用时: 35 ms, 内存消耗: 41.5 MB, 提交时间: 2024-06-09 10:29:46

class Solution {
    public int maxCoins(int[] nums) {
        int n = nums.length;
        int[][] rec = new int[n + 2][n + 2];
        int[] val = new int[n + 2];
        val[0] = val[n + 1] = 1;
        for (int i = 1; i <= n; i++) {
            val[i] = nums[i - 1];
        }
        for (int i = n - 1; i >= 0; i--) {
            for (int j = i + 2; j <= n + 1; j++) {
                for (int k = i + 1; k < j; k++) {
                    int sum = val[i] * val[k] * val[j];
                    sum += rec[i][k] + rec[k][j];
                    rec[i][j] = Math.max(rec[i][j], sum);
                }
            }
        }
        return rec[0][n + 1];
    }
}

java 解法, 执行用时: 110 ms, 内存消耗: 41.6 MB, 提交时间: 2024-06-09 10:29:21

class Solution {
    public int[][] rec;
    public int[] val;

    public int maxCoins(int[] nums) {
        int n = nums.length;
        val = new int[n + 2];
        for (int i = 1; i <= n; i++) {
            val[i] = nums[i - 1];
        }
        val[0] = val[n + 1] = 1;
        rec = new int[n + 2][n + 2];
        for (int i = 0; i <= n + 1; i++) {
            Arrays.fill(rec[i], -1);
        }
        return solve(0, n + 1);
    }

    public int solve(int left, int right) {
        if (left >= right - 1) {
            return 0;
        }
        if (rec[left][right] != -1) {
            return rec[left][right];
        }
        for (int i = left + 1; i < right; i++) {
            int sum = val[left] * val[i] * val[right];
            sum += solve(left, i) + solve(i, right);
            rec[left][right] = Math.max(rec[left][right], sum);
        }
        return rec[left][right];
    }
}

golang 解法, 执行用时: 36 ms, 内存消耗: 5.4 MB, 提交时间: 2023-05-24 17:36:11

func maxCoins(nums []int) int {
    n := len(nums)
    rec := make([][]int, n + 2)  // rec[i][j] 开区间(i, j)能拿到的最多硬币
    for i := 0; i < n + 2; i++ {
        rec[i] = make([]int, n + 2)
    }
    val := make([]int, n + 2)
    val[0], val[n+1] = 1, 1
    for i := 1; i <= n; i++ {
        val[i] = nums[i-1]
    }
    for i := n - 1; i >= 0; i-- {
        for j := i + 2; j <= n + 1; j++ {
            for k := i + 1; k < j; k++ {
                sum := val[i] * val[k] * val[j]
                sum += rec[i][k] + rec[k][j]
                rec[i][j] = max(rec[i][j], sum)
            }
        }
    }
    return rec[0][n+1]
}

func max(x, y int) int {
    if x > y {
        return x
    }
    return y
}

golang 解法, 执行用时: 152 ms, 内存消耗: 5.5 MB, 提交时间: 2023-05-24 17:35:19

func maxCoins(nums []int) int {
    n := len(nums)
    val := make([]int, n + 2)
    for i := 1; i <= n; i++ {
        val[i] = nums[i - 1]
    }
    val[0], val[n+1] = 1, 1
    rec := make([][]int, n + 2)
    for i := 0; i < len(rec); i++ {
        rec[i] = make([]int, n + 2)
        for j := 0; j < len(rec[i]); j++ {
            rec[i][j] = -1
        }
    }
    return solve(0, n + 1, val, rec)
}

func solve(left, right int, val []int, rec [][]int) int {
    if left >= right - 1 {
        return 0
    }
    if rec[left][right] != -1 {
        return rec[left][right]
    }
    for i := left + 1; i < right; i++ {
        sum := val[left] * val[i] * val[right]
        sum += solve(left, i, val, rec) + solve(i, right, val, rec)
        rec[left][right] = max(rec[left][right], sum)
    }
    return rec[left][right]
}

func max(x, y int) int {
    if x > y {
        return x
    }
    return y
}

python3 解法, 执行用时: 5568 ms, 内存消耗: 40 MB, 提交时间: 2023-05-24 17:34:46

class Solution:
    def maxCoins(self, nums: List[int]) -> int:
        n = len(nums)
        val = [1] + nums + [1]
        
        @lru_cache(None)
        def solve(left: int, right: int) -> int:
            if left >= right - 1:
                return 0
            
            best = 0
            for i in range(left + 1, right):
                total = val[left] * val[i] * val[right]
                total += solve(left, i) + solve(i, right)
                best = max(best, total)
            
            return best

        return solve(0, n + 1)

python3 解法, 执行用时: 2756 ms, 内存消耗: 18.1 MB, 提交时间: 2023-05-24 17:34:15

class Solution:
    def maxCoins(self, nums: List[int]) -> int:
        #nums首尾添加1,方便处理边界情况
        nums.insert(0,1)
        nums.insert(len(nums),1)

        store = [[0]*(len(nums)) for i in range(len(nums))]

        def range_best(i,j):
            m = 0 
            #k是(i,j)区间内最后一个被戳的气球
            for k in range(i+1,j): #k取值在(i,j)开区间中
                #以下都是开区间(i,k), (k,j)
                left = store[i][k]
                right = store[k][j]
                a = left + nums[i]*nums[k]*nums[j] + right
                if a > m:
                    m = a
            store[i][j] = m

        #对每一个区间长度进行循环
        for n in range(2,len(nums)): #区间长度 #长度从3开始,n从2开始
            #开区间长度会从3一直到len(nums)
            #因为这里取的是range,所以最后一个数字是len(nums)-1

            #对于每一个区间长度,循环区间开头的i
            for i in range(0,len(nums)-n): #i+n = len(nums)-1

                #计算这个区间的最多金币
                range_best(i,i+n)

        return store[0][len(nums)-1]

python3 解法, 执行用时: 6524 ms, 内存消耗: 40 MB, 提交时间: 2023-05-24 17:33:07

class Solution:
    def maxCoins(self, nums: List[int]) -> int:
        n = len(nums)
        nums = [1] + nums + [1]

        @cache
        def solve(L, R):
            # 要戳nums[L:R+1]
            if L > R:
                return 0

            # 把 L 留最后戳
            ret = nums[L-1]*nums[L]*nums[R+1] + solve(L+1, R)
            # 把 R 留最后戳
            ret = max(ret, nums[L-1]*nums[R]*nums[R+1] + solve(L, R-1))
            # 把k留最后戳
            for k in range(L+1, R):
                # 先戳 nums[L:k] 和 nums[k+1:R+1], 再戳 nums[k]
                cur = solve(L, k-1) + nums[L-1]*nums[k]*nums[R+1] + solve(k+1, R)
                ret = max(ret, cur)

            return ret
            
        return solve(1, n)

javascript 解法, 执行用时: 196 ms, 内存消耗: 43.9 MB, 提交时间: 2023-05-24 17:32:36

/**
 * @param {number[]} nums
 * @return {number}
 */
var maxCoins = function (nums) {
  let n = nums.length;
  // 添加两侧的虚拟气球
  let points = new Array(n + 2);
  points[0] = points[n + 1] = 1;
  for (let i = 1; i <= n; i++) {
    points[i] = nums[i - 1];
  }
  // base case 已经都被初始化为 0
  let dp = new Array(n + 2).fill(0).map(() => new Array(n + 2).fill(0));
  // 开始状态转移
  // i 应该从下往上
  for (let i = n; i >= 0; i--) {
    // j 应该从左往右
    for (let j = i + 1; j < n + 2; j++) {
      // 最后戳破的气球是哪个?
      for (let k = i + 1; k < j; k++) {
        // 择优做选择
        dp[i][j] = Math.max(
          dp[i][j],
          dp[i][k] + dp[k][j] + points[i] * points[j] * points[k]
        );
      }
    }
  }
  return dp[0][n + 1];
};

cpp 解法, 执行用时: 436 ms, 内存消耗: 10.2 MB, 提交时间: 2023-05-24 17:31:58

/**
当求戳爆开区间(i,j)内部所有气球可获的最大硬币数时,可以分为三步:

step 1: 选取一个最后戳爆的气球 k (需要选取每个可能的k去计算一遍,保留最大结果)

step 2: 戳爆开区间(i, k)内的气球,再戳爆开区间(k, j)内的气球,完成后开区间内只剩下气球 k, 其左右气球为 i , j

step 3: 戳爆气球 k, 获得硬币数为 nums[i]∗nums[k]∗nums[j]

当我们在开头和结尾加上边界值1时,数组长度为 len = nums.size() + 2,则我们的目标就是开区间(0, len-1)
 */
class Solution {
public:
    int maxCoins(vector<int>& nums) {
        // dp(i, j): 开区间(i, j)所能取得的最大硬币数量
        nums.insert(nums.begin(), 1);
        nums.push_back(1);
        int len = nums.size();
        vector<vector<int>> dp(len, vector<int>(len, 0));
        for(int i = len-1; i >=0; --i){ // i逆序:dp[k][j]中的k大于i
            for(int j = i+2; j <= len-1; ++j){ // j-i <= 1时区间为空,所以j从i+2开始
                for(int k = i+1; k < j; ++k){ // k取不到边界值,因为是空区间
                    dp[i][j] = max(dp[i][j], dp[i][k] + nums[i] * nums[k] * nums[j] + dp[k][j]);
                }
                
            }
        }
        return dp[0][len-1];
    }
};

上一题