dsadas
dsadasdasd
/**
这个题我感觉有点歧义,戳破的是第i+1个数,获得nums[i - 1] * nums[i] * nums[i + 1] , 如果i-1或i+1超出了数组的边界,那么就当它是一个数字为1的气球,为了尽可能获得大的,我们应该依次戳破最小的?
不会做,看解析:
dp[i][j]表示在开区间(i,j)能得到硬币数
你在 (i,j) 开区间得到的金币可以由 dp[i][k] 和 dp[k][j] 进行转移
如果你此刻选择戳爆气球 k,那么你得到的金币数量就是:total=dp[i][k]+val[i] * val[k] * val[j]+dp[k][j]
val[i] 表示 i 位置气球的数字 然后 (i,k) 和 (k,j) 也都是开区间
*/
class Solution {
public int maxCoins(int[] nums) {
//数组长度
int n = nums.length;
//中间数组,把两个边界之外的第一个数都放进去,也就是nums[-1] ,nums[n]
int[] temp = new int[n+2];
temp[0] =1;
temp[n+1] =1;
for(int i=0 ; i<n ; i++){
temp[i+1] = nums[i];
}
//数组已经建立好了temp
int[][] dp = new int[n+2][n+2];
//len表示开区间的长度,动态规划思想,解决小问题->大问题
for(int len=3 ; len<=n+2 ; len++){
//i表示开区间左端点
for(int i = 0 ; i <= n+2-len ; i++ ){
int res=0;
//K为开区间内的索引
for(int k=i+1 ; k < i+len-1 ; k++){
int left = dp[i][k];
int right = dp[k][i+len-1];
res = Math.max(res , left + temp[i] * temp[k] * temp[i+len-1] +right);
}
dp[i][i+len-1] = res;
}
}
return dp[0][n+1];
}
}
416
//首先我们先求出一半的值是多少,并且数组值得和必须是偶数
class Solution {
public boolean canPartition(int[] nums) {
int len = nums.length;
if(len == 0){
return false;
}
int sum = 0;
for(int num : nums){
sum += num;
}
if((sum & 1) == 1){
return false;
}
int target = sum / 2;
//也就是说求含有target即可,通过动态规划来做
boolean[][] dp = new boolean[len][target+1];
//dp[i][j]表示从[0,i]这个子区间中能挑选一些正整数,每个数只能用一次,使得这些数的和恰好等于j
//先填第0行,第一个数只能让容积为它自己的背包恰好装满(也就是边界)
if(nums[0] <= target){
dp[0][nums[0]] = true;
}
/*再想转移方程
不选择nums[i],[0,i-1]这个子区间已经有一部分元素,使得它们的和为j,dp[i][j] =true
选择nums[i],[0,i-1]这个子区间内的到一部分元素,使得它们的和为j-nums[i]
再填后面几行
*/
for(int i=1 ; i<len ; i++){
for(int j=1 ; j<=target ; j++){
//先把上一行抄下来再修正
dp[i][j] = dp[i-1][j];
if(nums[i] == j){
dp[i][j] = true;
continue;
}
if(nums[i] < j){
dp[i][j] = dp[i-1][j] || dp[i - 1][j - nums[i]];
}
}
}
return dp[len-1][target];
}
}
dsadas
//首先我们先求出一半的值是多少,并且数组值得和必须是偶数
class Solution {
public boolean canPartition(int[] nums) {
int len = nums.length;
int sum = 0;
for(int num : nums){
sum += num;
}
if((sum & 1) == 1){
return false;
}
int target = sum / 2;
//也就是说求含有target即可,通过动态规划来做
boolean[][] dp = new boolean[len][target+1];
//dp[i][j]表示从[0,i]这个子区间中能挑选一些正整数,每个数只能用一次,使得这些数的和恰好等于j
//先填第0行,第一个数只能让容积为它自己的背包恰好装满(也就是边界)
if(nums[0] <= target){
dp[0][nums[0]] = true;
}
/*再想转移方程
不选择nums[i],[0,i-1]这个子区间已经有一部分元素,使得它们的和为j,dp[i][j] =true
选择nums[i],[0,i-1]这个子区间内的到一部分元素,使得它们的和为j-nums[i]
再填后面几行
*/
for(int i=1 ; i<len ; i++){
for(int j=1 ; j<=target ; j++){
//先把上一行抄下来再修正
dp[i][j] = dp[i-1][j];
if(nums[i] == j){
dp[i][j] = true;
continue;
}
if(nums[i] < j){
dp[i][j] = dp[i-1][j] || dp[i - 1][j - nums[i]];
}
}
}
return dp[len-1][target];
}
}