题目描述
设一个n个节点的二叉树tree的中序遍历为(1,2,3,…,n),其中数字1,2,3,…,n为节点编号。每个节点都有一个分数(均为正整数),记第i个节点的分数为di,tree及它的每个子树都有一个加分,任一棵子树subtree(也包含tree本身)的加分计算方法如下:
subtree的左子树的加分× subtree的右子树的加分+subtree的根的分数。
若某个子树为空,规定其加分为1,叶子的加分就是叶节点本身的分数。不考虑它的空子树。
试求一棵符合中序遍历为(1,2,3,…,n)且加分最高的二叉树tree。要求输出tree的最高加分和前序遍历
输入
长度为n的序列,序列值为每个节点的分数(分数<100)如:5,7,1,2,10
输出
最高加分;前序遍历,如:145; 3 1 2 4 5
1 思路
若要使加分最高,则需让父节点尽可能小
2 拆分子问题
构建树的过程中,从当前序列找到值最小的节点作为父节点,节点左侧序列为左子树,右侧序列为右子树
3 计算
T[0,m]={ Node[k], left:T[0,k-1], right:T[k+1,m]}
4 代码
recursive DP
const treeArray = [5,7,1,2,10];
class CalTree {
constructor(options) {
this.treeArray = Array.isArray(options) ? options : [];
this.walkArr = [];
this.sum = 0;
}
getTreeRecursive() {
const newArr = this.getTreeRec(this.treeArray);
this.sum = this.getSum(newArr);
console.log(`前序遍历序列是: ${ this.walkArr.join(",") }`);
console.log(`最高加分是 ${this.sum}`); // 最高得分
}
getTreeRec(arr) {
const min = Math.min(...arr);
const item = {
value: min,
index: arr.indexOf(min)
};
if (arr.length === 1) {
return {
item,
left: null,
right: null
};
}
const leftArr = arr.slice(0, item.index);
const rightArr = arr.slice(item.index + 1, arr.length);
let obj = {};
obj.item = item;
obj.left = leftArr.length > 0 ? this.getTreeRec(leftArr):null;
obj.right = rightArr.length > 0 ? this.getTreeRec(rightArr) : null;
return obj;
}
getSum(obj) {
this.walkArr.push(obj.item.value);
if (!obj.left && !obj.right) {
return obj.item.value;
}
const left = obj.left ? this.getSum(obj.left) : 1;
const right = obj.right ? this.getSum(obj.right) : 1;
return obj.item.value + left * right;
}
}
new CalTree(treeArray).getTreeRecursive();
5 时间复杂度
主要过程是把序列一分为二分别建子树,第i次拆分的计算量是2的i次方,故时间复杂度为O(2的logn次方)
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。