Burst Balloons
2016-06-18 11:37
260 查看
题目描述:
Given
Find the maximum coins you can collect by bursting the balloons wisely.
Note:
(1) You may imagine
(2) 0 ≤
Example:
Given
Return
我先自己写了一个回溯算法,超时:
public int maxCoins(int[] nums) {
int[] leftIndexs=new int[nums.length];
int[] rightIndexs=new int[nums.length];
for(int i=0;i<leftIndexs.length;i++){
leftIndexs[i]=i-1;
rightIndexs[i]=i+1;
}
return getMaxCoins(nums, leftIndexs, rightIndexs);
}
public int getMaxCoins(int[] nums,int[] leftIndexs,int[] rightIndexs){
int max=0;
boolean visited=false;
for(int i=0;i<nums.length;i++){
if(nums[i]!=Integer.MAX_VALUE){
visited=true;
int leftvalue=leftIndexs[i]==-1?1:nums[leftIndexs[i]];
int rightvalue=rightIndexs[i]==nums.length?1:nums[rightIndexs[i]];
int num=nums[i]*leftvalue*rightvalue;
int rightLeftIndex=0,leftRightIndex=0;
if(rightIndexs[i]<nums.length){
rightLeftIndex=leftIndexs[rightIndexs[i]];
leftIndexs[rightIndexs[i]]=leftIndexs[i];
}
if(leftIndexs[i]>=0){
leftRightIndex=rightIndexs[leftIndexs[i]];
rightIndexs[leftIndexs[i]]=rightIndexs[i];
}
int value=nums[i];
nums[i]=Integer.MAX_VALUE;
num+=getMaxCoins(nums, leftIndexs, rightIndexs);
max=num>max?num:max;
if(rightIndexs[i]<nums.length){
leftIndexs[rightIndexs[i]]=rightLeftIndex;
}
if(leftIndexs[i]>=0){
rightIndexs[leftIndexs[i]]=leftRightIndex;
}
nums[i]=value;
}
}
if(!visited)
return 0;
return max;
}后来将这个算法优化了一点,将之前没有计算过的计算一遍,然后记录下来,当再次碰到的时候直接读取。
虽然性能上有所提高,但是还是超时了:
public class Solution {
public int maxCoins(int[] nums) {
int[] leftIndexs=new int[nums.length];
int[] rightIndexs=new int[nums.length];
for(int i=0;i<leftIndexs.length;i++){
leftIndexs[i]=i-1;
rightIndexs[i]=i+1;
}
int[] dp=new int[(int)Math.pow(2, nums.length)];
Arrays.fill(dp, -1);
return getMaxCoins(nums, leftIndexs, rightIndexs, 0, dp);
}
public int getMaxCoins(int[] nums,int[] leftIndexs,int[] rightIndexs,int key,int[] dp){
if(dp[key]!=-1)
return dp[key];
int max=0;
for(int i=0;i<nums.length;i++){
if(nums[i]!=Integer.MAX_VALUE){
int leftvalue=leftIndexs[i]==-1?1:nums[leftIndexs[i]];
int rightvalue=rightIndexs[i]==nums.length?1:nums[rightIndexs[i]];
int num=nums[i]*leftvalue*rightvalue;
int rightLeftIndex=0,leftRightIndex=0;
if(rightIndexs[i]<nums.length){
rightLeftIndex=leftIndexs[rightIndexs[i]];
leftIndexs[rightIndexs[i]]=leftIndexs[i];
}
if(leftIndexs[i]>=0){
leftRightIndex=rightIndexs[leftIndexs[i]];
rightIndexs[leftIndexs[i]]=rightIndexs[i];
}
int value=nums[i];
nums[i]=Integer.MAX_VALUE;
num+=getMaxCoins(nums, leftIndexs, rightIndexs, (int)(key+Math.pow(2, i)), dp);
max=num>max?num:max;
if(rightIndexs[i]<nums.length){
leftIndexs[rightIndexs[i]]=rightLeftIndex;
}
if(leftIndexs[i]>=0){
rightIndexs[leftIndexs[i]]=leftRightIndex;
}
nums[i]=value;
}
}
dp[key]=max;
return max;
}
}正确解法是:
举例来说,数组[A,B,C,D,E,F,G],代表任意数字。
首先去掉所有的零,在头和尾加上两个1表示边界。
最外层循环就是从A到G,代表了最后一个踩的气球。
假设遍历到C这个点,最后要踩C,那么C的值是固定的,为1 * C * 1。
然后考虑两边,左边的是以1和C为边界,求出最大值,右边是以C和1为边界求最大值,如图所示。
递归求出结果。
还要开一个二维数组记录中间结果提高效率。
最后的剩下一个气球为m的时候,可以获得的分数为 nums[-1]*nums[m]*nums
.
那么介于l, r之间的m, 有 dp[l][r] = max(dp[l][r], dp[l][m] + nums[l] * nums[m] * nums[r] + dp[m][r]).
l与r的跨度k从2开始逐渐增大;
三重循环依次枚举范围跨度k, 左边界l, 中点m, 右边界r = l + k
Java D&C with Memoization
public int maxCoins(int[] iNums) {
int[] nums = new int[iNums.length + 2];
int n = 1;
for (int x : iNums) if (x > 0) nums[n++] = x;
nums[0] = nums[n++] = 1;
int[][] memo = new int
;
return burst(memo, nums, 0, n - 1);
}
public int burst(int[][] memo, int[] nums, int left, int right) {
if (left + 1 == right) return 0;
if (memo[left][right] > 0) return memo[left][right];
int ans = 0;
for (int i = left + 1; i < right; ++i)
ans = Math.max(ans, nums[left] * nums[i] * nums[right]
+ burst(memo, nums, left, i) + burst(memo, nums, i, right));
memo[left][right] = ans;
return ans;
}Java DP
Given
nballoons, indexed from
0to
n-1. Each balloon is painted with a number on it represented by array
nums. You are asked to burst all the balloons. If the you burst balloon
iyou will get
nums[left] * nums[i] * nums[right]coins. Here
leftand
rightare adjacent indices of
i. After the burst, the
leftand
rightthen becomes adjacent.
Find the maximum coins you can collect by bursting the balloons wisely.
Note:
(1) You may imagine
nums[-1] = nums = 1. They are not real therefore you can not burst them.
(2) 0 ≤
n≤ 500, 0 ≤
nums[i]≤ 100
Example:
Given
[3, 1, 5, 8]
Return
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
我先自己写了一个回溯算法,超时:
public int maxCoins(int[] nums) {
int[] leftIndexs=new int[nums.length];
int[] rightIndexs=new int[nums.length];
for(int i=0;i<leftIndexs.length;i++){
leftIndexs[i]=i-1;
rightIndexs[i]=i+1;
}
return getMaxCoins(nums, leftIndexs, rightIndexs);
}
public int getMaxCoins(int[] nums,int[] leftIndexs,int[] rightIndexs){
int max=0;
boolean visited=false;
for(int i=0;i<nums.length;i++){
if(nums[i]!=Integer.MAX_VALUE){
visited=true;
int leftvalue=leftIndexs[i]==-1?1:nums[leftIndexs[i]];
int rightvalue=rightIndexs[i]==nums.length?1:nums[rightIndexs[i]];
int num=nums[i]*leftvalue*rightvalue;
int rightLeftIndex=0,leftRightIndex=0;
if(rightIndexs[i]<nums.length){
rightLeftIndex=leftIndexs[rightIndexs[i]];
leftIndexs[rightIndexs[i]]=leftIndexs[i];
}
if(leftIndexs[i]>=0){
leftRightIndex=rightIndexs[leftIndexs[i]];
rightIndexs[leftIndexs[i]]=rightIndexs[i];
}
int value=nums[i];
nums[i]=Integer.MAX_VALUE;
num+=getMaxCoins(nums, leftIndexs, rightIndexs);
max=num>max?num:max;
if(rightIndexs[i]<nums.length){
leftIndexs[rightIndexs[i]]=rightLeftIndex;
}
if(leftIndexs[i]>=0){
rightIndexs[leftIndexs[i]]=leftRightIndex;
}
nums[i]=value;
}
}
if(!visited)
return 0;
return max;
}后来将这个算法优化了一点,将之前没有计算过的计算一遍,然后记录下来,当再次碰到的时候直接读取。
虽然性能上有所提高,但是还是超时了:
public class Solution {
public int maxCoins(int[] nums) {
int[] leftIndexs=new int[nums.length];
int[] rightIndexs=new int[nums.length];
for(int i=0;i<leftIndexs.length;i++){
leftIndexs[i]=i-1;
rightIndexs[i]=i+1;
}
int[] dp=new int[(int)Math.pow(2, nums.length)];
Arrays.fill(dp, -1);
return getMaxCoins(nums, leftIndexs, rightIndexs, 0, dp);
}
public int getMaxCoins(int[] nums,int[] leftIndexs,int[] rightIndexs,int key,int[] dp){
if(dp[key]!=-1)
return dp[key];
int max=0;
for(int i=0;i<nums.length;i++){
if(nums[i]!=Integer.MAX_VALUE){
int leftvalue=leftIndexs[i]==-1?1:nums[leftIndexs[i]];
int rightvalue=rightIndexs[i]==nums.length?1:nums[rightIndexs[i]];
int num=nums[i]*leftvalue*rightvalue;
int rightLeftIndex=0,leftRightIndex=0;
if(rightIndexs[i]<nums.length){
rightLeftIndex=leftIndexs[rightIndexs[i]];
leftIndexs[rightIndexs[i]]=leftIndexs[i];
}
if(leftIndexs[i]>=0){
leftRightIndex=rightIndexs[leftIndexs[i]];
rightIndexs[leftIndexs[i]]=rightIndexs[i];
}
int value=nums[i];
nums[i]=Integer.MAX_VALUE;
num+=getMaxCoins(nums, leftIndexs, rightIndexs, (int)(key+Math.pow(2, i)), dp);
max=num>max?num:max;
if(rightIndexs[i]<nums.length){
leftIndexs[rightIndexs[i]]=rightLeftIndex;
}
if(leftIndexs[i]>=0){
rightIndexs[leftIndexs[i]]=leftRightIndex;
}
nums[i]=value;
}
}
dp[key]=max;
return max;
}
}正确解法是:
举例来说,数组[A,B,C,D,E,F,G],代表任意数字。
首先去掉所有的零,在头和尾加上两个1表示边界。
最外层循环就是从A到G,代表了最后一个踩的气球。
假设遍历到C这个点,最后要踩C,那么C的值是固定的,为1 * C * 1。
然后考虑两边,左边的是以1和C为边界,求出最大值,右边是以C和1为边界求最大值,如图所示。
递归求出结果。
还要开一个二维数组记录中间结果提高效率。
最后的剩下一个气球为m的时候,可以获得的分数为 nums[-1]*nums[m]*nums
.
那么介于l, r之间的m, 有 dp[l][r] = max(dp[l][r], dp[l][m] + nums[l] * nums[m] * nums[r] + dp[m][r]).
l与r的跨度k从2开始逐渐增大;
三重循环依次枚举范围跨度k, 左边界l, 中点m, 右边界r = l + k
Java D&C with Memoization
public int maxCoins(int[] iNums) {
int[] nums = new int[iNums.length + 2];
int n = 1;
for (int x : iNums) if (x > 0) nums[n++] = x;
nums[0] = nums[n++] = 1;
int[][] memo = new int
;
return burst(memo, nums, 0, n - 1);
}
public int burst(int[][] memo, int[] nums, int left, int right) {
if (left + 1 == right) return 0;
if (memo[left][right] > 0) return memo[left][right];
int ans = 0;
for (int i = left + 1; i < right; ++i)
ans = Math.max(ans, nums[left] * nums[i] * nums[right]
+ burst(memo, nums, left, i) + burst(memo, nums, i, right));
memo[left][right] = ans;
return ans;
}Java DP
public int maxCoins(int[] iNums) { int[] nums = new int[iNums.length + 2]; int n = 1; for (int x : iNums) if (x > 0) nums[n++] = x; nums[0] = nums[n++] = 1; int[][] dp = new int ; for (int k = 2; k < n; ++k) for (int left = 0; left < n - k; ++left) { int right = left + k; for (int i = left + 1; i < right; ++i) dp[left][right] = Math.max(dp[left][right], nums[left] * nums[i] * nums[right] + dp[left][i] + dp[i][right]); } return dp[0][n - 1]; }
相关文章推荐
- android6.0问题汇总
- java ArrayList<Map<String,String>>排序
- Bzoj1257[CQOI2007]余数之和sum
- 最简单的js 判断密码强度
- 量化交易策略
- LeetCode-206 Reverse Linked List
- 使用ExpandoObject来实现多个Model传送至视图
- 【06-18】CentOS使用笔记
- Hibernate one to one映射关系
- 查找包含特定字符最短片段
- ACM程序设计选修课——1081: 堆(BFS)
- win10网络显示“WLAN没有有效的IP配置”
- 【Unity Shaders】学习笔记——渲染管线
- ddd
- Win10下VS2015(WDK10)驱动开发环境配置
- 357. Count Numbers with Unique Digits
- 实际情况来看,还是yield很爽
- Java设计模式(十) 你真的用对单例模式了吗?
- 第七章 SpringMVC数据类型转换—注解式控制器的数据验证、类型转换及格式化
- 编程的智慧