链接:https://leetcode-cn.com/problems/burst-balloons/
题目:
有 n 个气球,编号为0 到 n-1,每个气球上都标有一个数字,这些数字存在数组 nums 中,
现在要求戳破所有的气球。每当戳破一个气球 i 时,可以获得 nums[left] * nums[i] * nums[right] 个硬币,其中 left 和 right 代表和 i 相邻的两个气球的序号,注意当戳破了气球 i 后,气球 left 和气球 right 就变成了相邻的气球,
求所能获得硬币的最大数量
说明:
可以假设 nums[-1] = nums[n] = 1,但注意它们不是真实存在的所以并不能被戳破。0 ≤ n ≤ 500, 0 ≤ nums[i] ≤ 100
解题思路:
解法一,我的想法是通过递归回溯来找到所能获取的最大数量的硬币,然而提交后提示时间超时,这种方法的时间复杂度达到了O(N!),其中N为气球的个数
1 import java.util.List; 2 import java.util.ArrayList; 3 4 public class Solution { 5 public int maxCoins(int[] nums) { 6 List<Integer> arr = new ArrayList(); 7 for(int i = 0; i < nums.length; i++) { 8 arr.add(nums[i]); 9 } 10 return helper(arr); 11 } 12 13 public int helper(List<Integer> arr) { 14 if(arr.size() == 0) return 0; 15 int pre = 0, next = 0; 16 int max = 0; 17 int len = arr.size(); 18 for(int i = 0; i < len; i++) { 19 pre = i == 0 ? 1 : arr.get(i - 1); 20 next = i == arr.size()-1 ? 1 : arr.get(i + 1); 21 int cur = arr.get(i); 22 arr.remove(i); 23 max = Math.max(max, pre*cur*next + helper(arr)); 24 arr.add(i, cur); 25 } 26 return max; 27 } 28 }
时间复杂度:O(N!);空间复杂度:O(N),其中N为气球的个数
解法二(看这里),随机选取一点作为分界点,先算出左右两边的最大值,然后算出当前的最大值,仍然超时,时间复杂度为O(N!),空间复杂度O(1),其中N为气球的个数。与解法一的区别在于,解法一是先戳破当前节点,然后计算当前节点被戳破的情况下,计算剩余节点的情况,而解法二采取的是先把剩余的节点计算出最大值,再戳破当前节点。
1 import java.util.List; 2 import java.util.ArrayList; 3 4 public class Solution { 5 public int maxCoins(int[] nums) { 6 return maxCoin(nums, 0, nums.length - 1); 7 } 8 9 public int maxCoin(int[] nums, int left, int right) { 10 if(left > right) return 0; 11 12 int pre = 0, next = 0; 13 int max = 0; 14 for(int i = left; i <= right; i++) { 15 pre = left == 0 ? 1 : nums[left - 1]; 16 next = right == nums.length - 1 ? 1 : nums[right + 1]; 17 max = Math.max(max, pre*nums[i]*next + maxCoin(nums, left, i - 1) + maxCoin(nums, i + 1, right)); 18 } 19 return max; 20 } 21 }
解法三(看这里),动态规划,dp[i][j]表示将[i+1, j-1]范围的气球全部戳破可以获得的最大硬币数量。
1 public class Solution { 2 public int maxCoins(int[] nums) { 3 if(nums == null || nums.length == 0) return 0; 4 int length = nums.length + 2; 5 int[] arr = new int[length]; 6 arr[0] = 1; 7 arr[length - 1] = 1; 8 for(int i = 1; i < length - 1; i++) { 9 arr[i] = nums[i - 1]; 10 } 11 int[][] dp = new int[length][length]; 12 for(int len = 2; len < length; len++) { 13 for(int i = 0; i < length - len; i++) { 14 int j = i + len; 15 for(int k = i + 1; k < j; k++) { 16 dp[i][j] = Math.max(dp[i][j], arr[i]*arr[k]*arr[j] + dp[i][k] + dp[k][j]); 17 } 18 } 19 } 20 return dp[0][length - 1]; 21 } 22 }