Google算法题:吹气球/合石子(区间动态规划)

本文介绍了Google的一道算法题,即吹气球问题,涉及动态规划解决策略。给定n个气球,每个带有分数,目标是找到最佳顺序吹爆所有气球以最大化总分数。题目对气球编号和分数进行了规定,并提供了一个示例,展示如何求解得到最大分数167。

https://mp.weixin.qq.com/s?__biz=MzA5MzE4MjgyMw==&mid=401898450&idx=1&sn=fe4f8fa3bb37c5efce14a5567a523422&mpshare=1&scene=1&srcid=0317yIVobCsqLWHoivnzZ7WV&key=5657e61c2ec7753da39602d28107ebab91eb8417c110c48c91138a9dba63822c2b01c44800fdb03844e1a724e6be1351c8f8e7c90c1f4679cf244f4b4ace8a7cd4b06f951334c07a3c1278c2de092f7d&ascene=0&uin=MTUyMzg3NjAwMA%3D%3D&devicetype=iMac+MacBookAir7%2C1+OSX+OSX+10.12.3+build(16D32)&version=12020010&nettype=WIFI&fontScale=100&pass_ticket=0AiIToHJN8yqpuqRAsA5PaaQMJr8KtvlnZ2EqkX0zx%2BEZweRvHKyF%2ByjmycpUbVn

http://blog.youkuaiyun.com/zlambert/article/details/65934717


题目描述 

有n个气球,编号为0到n-1,每个气球都有一个分数,存在nums数组中。每次吹气球i可以得到的分数为 nums[left] * nums[i] * nums[right],left和right分别表示i气球相邻的两个气球。当i气球被吹爆后,其左右两气球即为相邻。要求吹爆所有气球,得到最多的分数。

注释: 
(1) 你可以假设nums[-1] = nums[n] = 1
(2) 0 ≤ n ≤ 500, 0 ≤ nums[i] ≤ 100

Example:

给出[3, 1, 5, 8]

返回167


class Solution {
	int max = Integer.MIN_VALUE;
	
	//枚举所有case
	public int solve(int[] nums){
		if(nums==null) return max;
		
		int n = nums.length;
		List<Integer> list = new ArrayList<Integer>();
		for(int i=0; i<n; i++){
			list.add(nums);
		}
		
		int res=0;
		process(list, res);
		
		return max;
	}
	public void process(List list, int res){
		if(list.size()==0)
			max = max(max, res);
		for(int i=0; i<list.size(); i++){
			//blow ballon i
			int curMul = (i-1<0?1:list.get(i-1))*list.get(i)*(i+1>=n?1:list.get(i+1));
			res += curMul;
			int cur = list.remove(i);
			process(list, res);
			res -= curMul;
			list.add(i, cur);
		}
	}
	
	//递归-记忆
	public int solve_memo(int[] nums){
		int n = nums.length;
		int[] arrs = new int[n+2];
		for(int i=0; i<n; i++){
			arrs[i+1] = nums[i];
		}
		arrs[0]=1;
		arrs[n+1]=1;
		
		//dp[i][j]表示吹爆i~j间的气球(包含i、j)能得到的最大收益
		int[][] dp = new dp[n+2][n+2];
		process_memo(arrs, dp, 1, n);
		
		return dp[1][n];
	}
	public int process_memo(int[] nums, int[][] dp, int s, int e){
		if(dp[s][e]>0)
			return dp[s][e];
		int maxCur=0;
		for(int k=s, k<=e; k++){
			int left = process(dp, s, k-1);
			int right = process(dp, s+1, e);
			int mid = nums[s-1]*nums[k]*nums[e+1];
			maxCur = Math.max(maxCur, left+mid+right);
		}
		dp[s][e] = maxCur;
		return maxCur;
	}
	
	//动态规划
	public int solve_dp(int[] nums){
		if(nums==null) return max;
			
		int n = nums.length;
		int[] arrs = new int[n+2];
		for(int i=0; i<n; i++){
			arrs[i+1] = nums[i];
		}
		arrs[0]=1;
		arrs[n+1]=1;
		
		//dp[i][j]表示吹爆i~j间的气球(包含i、j)能得到的最大收益
		int[][] dp = new int[n+1][n+1];
		
		//状态转移
		for(int len=1; len<=n; len++){
			for(int s=1; s<=n; s++){
				int curMax = 0;
				int e=s+len-1;
				for(int k=s; k<=e; k++){
					curMax = Math.max(curMax, dp[s][k-1]+dp[k+1][e]+arrs[s-1]*arrs[k]*arrs[e+1]);
				}
				dp[i][j] = curMax;
			}
		}
		
		return dp[1][n];
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值