剑指 Offer 07. 重建二叉树
输入某二叉树的前序遍历和中序遍历的结果,请构建该二叉树并返回其根节点。 假设输入的前序遍历和中序遍历的结果中都不含重复的数字。
提议理解: 根据二叉树的先序遍历和中序遍历,推出二叉树 先序遍历 根左右 中序遍历 左根右 先序和中序的相似出拆分
- 如果只考虑左子树,则先序和中序的顺序互反
- 只考虑右子树,则先序和中序顺序相同
- 根据次特点,可以使用递推进行运算,先序遍历的第一个数就是根节点
- 使用栈进行辅助计算stack,根节点为root
preorder = [3, 9, 1, 2, 20, 15, 7] inorder = [1, 9, 2, 3, 15, 20, 7] 首先可以确定根节点为3,设先序遍历当前索引为i 开始从1开始,0已确定为头结点,后序遍历当前索引为rightIndex 如果preorder[i]!== inorder[rightIndex], 则preorder[i]为root的左节点,将节点preorder[i]存入栈中 否则preorder[i]就是某个父级或祖先级节点的右节点,栈中无数据则为根据2直接为右节点;栈中有数据则回溯父件点,根据1,rightIndex++,执行出栈操作, 找到不同处则为该节点的右节点
var buildTree = function(preorder, inorder) {
if (!preorder.length || !inorder.length) {
return null
}
let root = new TreeNode(preorder[0])
let stack = [];
stack.push(root);
let rightIndex = 0;
for (let i = 1; i < preorder.length; i++) {
let pre = preorder[i];
let node = stack[stack.length - 1] || null;
if (node.val !== inorder[rightIndex]) {
node.left = new TreeNode(pre)
stack.push(node.left)
} else {
while (stack.length && stack[stack.length - 1].val === inorder[rightIndex]) {
node = stack.pop();
rightIndex++;
}
node.right = new TreeNode(pre)
stack.push(node.right)
}
}
};
剑指 Offer 16. 数值的整数次方
实现 pow(x, n) ,即计算 x 的 n 次幂函数(即,xn)。不得使用库函数,同时不需要考虑大数问题。
题意理解: 计算x的n次方,不使用函数库 二分+递归
- 特殊情况处理,x为0直接返回0,n为0直接返回1,n为1返回x,n为-1返回倒数
- 判断n的奇偶性,偶数次直接拆;奇数次向下取整,多乘一次x
提示: -100.0 < x < 100.0 -231 <= n <= 231-1 -104 <= xn <= 104
var myPow = function(x, n) {
if (x === 0) return 0;
if (n === 0) return 1;
if (n === 1) return x;
if (n === -1) return 1 / x;
if (n % 2 === 0) {
let a = myPow(x, n / 2);
return a * a
} else {
let b = myPow(x, (n - 1) / 2);
return b * b * x
}
};
剑指 Offer 33. 二叉搜索树的后序遍历序列
输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历结果。如果是则返回 true,否则返回 false。假设输入的数组的任意两个数字都互不相同。
提议理解: 输入一个数组判断是否为二叉搜索树的后序遍历结果 二叉搜索树,左小于根,右大于根 利用后序遍历 左 右 根 他的倒叙为根 右 左 输入的数组最后一个数为根节点
- 初始化root用来存储当前的右节点,初始化为一个大数
- 栈用来存储右节点和根节点
- 出栈操作完成root永远存的是当前以遍历的最大右节点
- 当栈中有数据,且栈顶元素大于当前元素,则进行出栈操作,root=出栈数
- 当前数大于栈顶数据时,表示此节点不是左节点,进行入栈操作
- 当出现root小于当前遍历的节点时,返回false
var verifyPostorder = function(postorder) {
const stack = [];
let root = Number.MAX_VALUE;
for (let i = postorder.length - 1; i >= 0; i--) {
if (postorder[i] > root) return false;
while (stack.length && stack[stack.length - 1] > postorder[i]) {
root = stack.pop();
}
stack.push(postorder[i]);
}
return true;
}
递推
- 输入的数组最后一个数为根节点
- 根据这个进行数组拆分,拆分成若干
- 索引左和右,当左大于等于有索引是返回true
- 左节点都小于根节点,右节点都大于根节点
- 采用累加进行判断,即做到第一个大于节点的数,此数左边都是左节点进行索引累加,剩下的大于根节点的索引累加
- 如果累加后索引不等于根节点的索引,则不满足条件返回false
var verifyPostorder = function(postorder) {
function recur(postorder, l, r) {
if (l >= r) return true;
let left = l;
while (postorder[left] < postorder[r]) {
left++;
}
let m = left;
while (postorder[left] > postorder[r]) {
left++;
}
return p == r && recur(postorder, l, m - 1) && recur(postorder, m, r - 1);
}
return recur(postorder, 0, postorder.length - 1)
}