java动态规划之数字三角形_动态规划练习题-数字三角形

问题描述:

747b13e7b8ff0de5e46d8f96c0b42b37.png

在上面的数字三角形中寻找一条从顶部到底边的路径,使得路径上所经过的数字之和最大。

路径上的每一步都只能往左下或 右下走。只需要求出这个最大和即可,不必给出具体路径。 三角形的行数大于1小于等于100,数字为 0 - 99

输入:

三角形序列:[[7],[3,8],[8,1,0],[2,7,4,4],[4,5,2,6,5]]

输出:

最大和,走过的数字序列

1 思路

把三角形看做一个二叉树,根节点为第一层,往第i+1层走时,是在第i层的基础上增加i+1个可选项,用到达第i层的路径和加上可选项,将有最大和的可选项纳入路径

2 拆分子问题

第i层的每个节点都有其最大路径和,往第i+1层走时,每个节点都有两个选项,因此可以计算得到第i+1层每个节点的最大路径和

3 计算

以w(i)(k)表示第i层的第k个节点的值,以S(i+1)作为到达第i+1层的最大路径和,以Sk(i+1)作为第i+1层第k个节点的最大路径和,其中1<=k<=i+1,S(i+1)=max{ Sk(i) + max{w(i+1)(k),w(i+1)(k+1)}, 其中1<=k<=i}

4 代码

bottom-up DP

const numbers = [[7], [3, 8], [8, 1, 0], [2, 7, 4, 4], [4, 5, 2, 6, 5]];

class CalTree {

constructor(numbers) {

this.numbers = numbers;

this.sums = numbers.map((item,rowIndex) => {

return item.map((item, index) => {

return rowIndex === 0 && index === 0 ? item : 0;

});

});

this.path = numbers.map(item => {

return item.map(item => item);

});

}

getSum() {

for (let i = 0;i

let nextSums = this.sums[i+1];

let curSums = this.sums[i];

let nextItems = this.numbers[i + 1];

for (let index = 0; index < curSums.length; index++){

const item = curSums[index];

const temp1 = item + nextItems[index];

if (temp1 > nextSums[index]) {

nextSums[index] = temp1;

this.path[i+1][index] = [].concat(this.path[i][index], nextItems[index]);

}

const temp2 = item + nextItems[index + 1];

if (temp2 > nextSums[index + 1]) {

nextSums[index + 1] = temp2;

this.path[i+1][index + 1] = [].concat(this.path[i][index], nextItems[index + 1]);

}

}

}

const lastSumArr = this.sums[this.sums.length - 1];

const lastPathArr = this.path[this.sums.length - 1];

let maxSum = 0, maxSumPath = [];

lastSumArr.forEach((item,index) => {

if (item > maxSum) {

maxSum = item;

maxSumPath = lastPathArr[index];

}

});

console.log("最大和是:", maxSum, ", 路径为:", maxSumPath.join(","));

}

}

new CalTree(numbers).getSum();

recurssive DP

const numbers = [[7], [3, 8], [8, 1, 0], [2, 7, 4, 4], [4, 5, 2, 6, 5]];

class CalTree {

constructor(numbers) {

this.numbers = numbers;

this.sums = numbers.map((item,rowIndex) => {

return item.map((item, index) => {

return rowIndex === 0 && index === 0 ? item : 0;

});

});

this.path = [].concat(numbers);

}

getSumRecursive() {

let lastArr = this.sums[this.sums.length - 1];

for (let i = 0; i < lastArr.length; i++){

this.cal(this.sums.length - 1, i);

}

const lastSumArr = this.sums[this.sums.length - 1];

const lastPathArr = this.path[this.sums.length - 1];

let maxSum = 0, maxSumPath = [];

lastSumArr.forEach((item, index) => {

if (item > maxSum) {

maxSum = item;

maxSumPath = lastPathArr[index];

}

});

console.log("最大和是:", maxSum, ", 路径为:", maxSumPath.reverse().join(","));

}

cal(depth, index) {

if (this.sums[depth][index]) {

return this.sums[depth][index];

}

const curItem = this.numbers[depth][index];

const upSums = this.sums[depth - 1];

const temp = [].concat(this.path[depth][index]);

if (index > 0) {

const temp2 = this.cal(depth - 1, index - 1) + curItem;

if (temp2 > this.sums[depth][index]) {

this.sums[depth][index] = temp2;

this.path[depth][index] = [].concat(temp, this.numbers[depth - 1][index - 1]);

}

}

if (index < upSums.length) {

const temp1 = this.cal(depth - 1, index) + curItem;

if (temp1 > this.sums[depth][index]) {

this.sums[depth][index] = temp1;

this.path[depth][index] = [].concat(temp, this.numbers[depth - 1][index]);

}

}

return this.sums[depth][index];

}

}

new CalTree(numbers).getSumRecursive();

5 时间复杂度

令三角形的数字个数为n,可以发现,除了最底行,其他行的每个数字仅参与两次计算,故时间复杂度为O(n)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值