题目链接:226. 翻转二叉树
给你一棵二叉树的根节点?root
?,翻转这棵二叉树,并返回其根节点。
示例 1:
输入:root = [4,2,7,1,3,6,9] 输出:[4,7,2,9,6,3,1]
示例 2:
输入:root = [2,1,3] 输出:[2,3,1]
示例 3:
输入:root = [] 输出:[]
提示:
[0, 100]
?内-100 <= Node.val <= 100
文章讲解:代码随想录
视频讲解:听说一位巨佬面Google被拒了,因为没写出翻转二叉树 | LeetCode:226.翻转二叉树_哔哩哔哩_bilibili
思路:递归的翻转左子树,再递归的翻转右子树,然后翻转当前节点的左孩子和右孩子。
前序遍历
/**
* Definition for a binary tree node.
* function TreeNode(val, left, right) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
*/
/**
* @param {TreeNode} root
* @return {TreeNode}
*/
var invertTree = function(root) {
if (root) {
// 翻转当前节点的子节点
let _ = root.left;
root.left = root.right;
root.right = _;
invertTree(root.left); // 递归的翻转左子树
invertTree(root.right); // 递归的翻转右子树
}
return root;
};
后序遍历
/**
* Definition for a binary tree node.
* function TreeNode(val, left, right) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
*/
/**
* @param {TreeNode} root
* @return {TreeNode}
*/
var invertTree = function(root) {
if (root) {
invertTree(root.left); // 递归的翻转左子树
invertTree(root.right); // 递归的翻转右子树
// 翻转当前节点的子节点
let _ = root.left;
root.left = root.right;
root.right = _;
}
return root;
};
中序遍历
中序遍历的写法和前序、后续稍微有点不同,原因在于中序遍历的处理顺序是左中右,对中间节点翻转处理后,右子树翻转到了左边,代码逻辑要做处理。
/**
* Definition for a binary tree node.
* function TreeNode(val, left, right) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
*/
/**
* @param {TreeNode} root
* @return {TreeNode}
*/
var invertTree = function(root) {
if (root) {
// 翻转当前节点的子节点
invertTree(root.left); // 递归的翻转左子树
let _ = root.left;
root.left = root.right;
root.right = _;
invertTree(root.left); // 因为中序遍历的处理顺序是左中右,对中间节点翻转处理后,右节点翻转到了左边,因此这里应该递归的翻转左子树
}
return root;
};
分析:时间复杂度为 O(n),空间复杂度为 O(logn)。
思路:对二叉树进行层序遍历,翻转每个节点的左右孩子。
/**
* Definition for a binary tree node.
* function TreeNode(val, left, right) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
*/
/**
* @param {TreeNode} root
* @return {TreeNode}
*/
var invertTree = function(root) {
const queue = [];
if (root) {
queue.push(root);
}
while (queue.length > 0) {
const node = queue.shift();
// 翻转当前节点的左右孩子
let _ = node.left;
node.left = node.right;
node.right = _;
node.left && queue.push(node.left);
node.right && queue.push(node.right);
}
return root;
};
分析:时间复杂度为 O(n),空间复杂度为 O(n)。
思路:使用迭代写法的遍历写法来完成二叉树翻转。
前序遍历
/**
* Definition for a binary tree node.
* function TreeNode(val, left, right) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
*/
/**
* @param {TreeNode} root
* @return {TreeNode}
*/
var invertTree = function(root) {
const stack = [];
if (root) {
stack.push(root);
}
while (stack.length > 0) {
const node = stack.pop();
// 中
const _ = node.left;
node.left = node.right;
node.right = _;
node.right && stack.push(node.right); // 右
node.left && stack.push(node.left); // 左
}
return root;
};
中序遍历
这里需要注意对右孩子的处理已经和标准中序遍历写法有了区别。
/**
* Definition for a binary tree node.
* function TreeNode(val, left, right) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
*/
/**
* @param {TreeNode} root
* @return {TreeNode}
*/
var invertTree = function(root) {
const stack = [];
let cur = root;
while (stack .length > 0 || cur) {
if (cur) {
stack.push(cur);
cur = cur.left; // 左
} else {
// 中
cur = stack.pop();
let _ = cur.left;
cur.left = cur.right;
cur.right = _;
cur = cur.left; // “右”
}
}
return root;
};
后续遍历
/**
* Definition for a binary tree node.
* function TreeNode(val, left, right) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
*/
/**
* @param {TreeNode} root
* @return {TreeNode}
*/
var invertTree = function(root) {
const stack = [];
if (root) {
stack.push(root);
}
while (stack.length > 0) {
const node = stack.pop();
// 中
const _ = node.left;
node.left = node.right;
node.right = _;
node.left && stack.push(node.left); // 左
node.right && stack.push(node.right); // 右
}
return root;
};
前序遍历(统一写法)
/**
* Definition for a binary tree node.
* function TreeNode(val, left, right) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
*/
/**
* @param {TreeNode} root
* @return {TreeNode}
*/
var invertTree = function(root) {
const stack = [];
if (root) {
stack.push(root);
}
while (stack.length > 0) {
let node = stack.pop();
if (node) {
node.right && stack.push(node.right); // 右
node.left && stack.push(node.left); // 左
stack.push(node); // 中
stack.push(null);
} else {
node = stack.pop();
const _ = node.left;
node.left = node.right;
node.right = _;
}
}
return root;
};
中序遍历(统一写法)
统一写法中的中序遍历由于使用的是标记法,在对节点处理之前,该节点的左孩子、该节点、该节点的右孩子已经以固定顺序入栈了,因此不会出现前面的已经交换左右子树导致继续遍历时要调整方向。
/**
* Definition for a binary tree node.
* function TreeNode(val, left, right) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
*/
/**
* @param {TreeNode} root
* @return {TreeNode}
*/
var invertTree = function(root) {
const stack = [];
if (root) {
stack.push(root);
}
while (stack.length > 0) {
let node = stack.pop();
if (node) {
node.right && stack.push(node.right); // 右
stack.push(node); // 中
stack.push(null);
node.left && stack.push(node.left); // 左
} else {
node = stack.pop();
const _ = node.left;
node.left = node.right;
node.right = _;
}
}
return root;
};
后续遍历(统一写法)
/**
* Definition for a binary tree node.
* function TreeNode(val, left, right) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
*/
/**
* @param {TreeNode} root
* @return {TreeNode}
*/
var invertTree = function(root) {
const stack = [];
if (root) {
stack.push(root);
}
while (stack.length > 0) {
let node = stack.pop();
if (node) {
stack.push(node); // 中
stack.push(null);
node.right && stack.push(node.right); // 右
node.left && stack.push(node.left); // 左
} else {
node = stack.pop();
const _ = node.left;
node.left = node.right;
node.right = _;
}
}
return root;
};
分析:时间复杂度为 O(n),空间复杂度为 O(logn)。
本题使用任何一种二叉树的遍历方式都可以解决(中序遍历有点绕,不太建议),本质是要交换每个节点的左右孩子,写出了这么多种遍历的代码,更加加深了我对二叉树遍历的理解。