二叉树
226. 翻转二叉树:给你一棵二叉树的根节点 root
,翻转这棵二叉树,并返回其根节点。
思路:通常遇到树结构的题目我们应该首先考虑递归,这道题使用递归就非常简单,只需要交换左右子节点:
function invertTree(root: TreeNode | null): TreeNode | null {
if (!root) return null;
let leftTree = invertTree(root.left);
let rightTree = invertTree(root.right);
// 交换左右子节点
root.left = rightTree;
root.right = leftTree;
return root;
};
使用栈结构:递归和栈的解法通常是可以相互转换的,我们声明一个栈并将根节点加入进去,while循环只要栈不为空,循环内首先取出栈顶元素,交换左右子节点,之后将左右子节点入栈:
function invertTree(root: TreeNode | null): TreeNode | null {
if (!root) return null;
const stack: TreeNode[] = [root];
while (stack.length) {
const cur = stack.pop()!;
// 交换左右子节点
[cur.left, cur.right] = [cur.right, cur.left];
if (cur.left) stack.push(cur.left);
if (cur.right) stack.push(cur.right);
}
return root;
}
124. 二叉树中的最大路径和:二叉树中的 路径 被定义为一条节点序列,序列中每对相邻节点之间都存在一条边。同一个节点在一条路径序列中 至多出现一次 。该路径 至少包含一个 节点,且不一定经过根节点。
路径和是路径中各节点值的总和。
给你一个二叉树的根节点 root,返回其最大路径和。
思路:首先应该意识到要使用递归,然后我们应该想要知道左右子树能提供的最大路径和,这样可以算出经过该root节点的最大路径和,然后取以所有节点为根节点并经过节点的最大值即可:
function maxPathSum(root: TreeNode | null): number {
let res: number = -Infinity;
// 获取经过节点的最大一侧路径和
function getMaxSideSum(root: TreeNode | null): number {
if (!root) return 0;
// 如果左右路径和小于0 就取0
const leftSideMax = Math.max(0, getMaxSideSum(root.left));
const rightSideMax = Math.max(0, getMaxSideSum(root.right));
// 经过root节点的最大路径和
res = Math.max(res, (leftSideMax + root.val + leftSideMax));
// 返回经过节点最大一侧路径和
return Math.max(leftSideMax, rightSideMax) + root.val;
}
getMaxSideSum(root);
return res;
}
动态规划
62. 不同路径:一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。
问总共有多少条不同的路径?
思路:这是一道典型的动态规划问题,状态转移方程很容易就能看出来:dp[m][n] = dp[m- 1][n] + dp[m][n-1],初始化状态为第一列和第一行的每个方格的路径皆为1,那么:
function uniquePaths(m: number, n: number): number {
if (m === 1 || n == 1) return 1;
// 声明数组
const table: number[][] = Array.from({ length: m }, () =>
new Array(n).fill(1)
);
// 从第二列第二行遍历即可 第一列第一行均为1
for (let i = 1; i < m; i++) {
for (let j = 1; j < n; j++) {
table[i][j] = table[i - 1][j] + table[i][j - 1];
}
}
return table[m - 1][n - 1];
}
剑指 Offer 47. 礼物的最大价值:在一个 m*n 的棋盘的每一格都放有一个礼物,每个礼物都有一定的价值(价值大于 0)。你可以从棋盘的左上角开始拿格子里的礼物,并每次向右或者向下移动一格、直到到达棋盘的右下角。给定一个棋盘及其上面的礼物的价值,请计算你最多能拿到多少价值的礼物?
思路:这题跟上一题非常相似,这题的状态转移方程是dp[m][n] = dp[m][n] + Math.max(dp[n - 1][m], dp[n][m - 1]),初始状态则是第一列和第一排的dp[i] = dp[i] + dp[i - 1],实现也非常简单:
function maxValue(grid: number[][]): number {
const deep = grid.length;
const width = grid[0].length;
for (let i = 0; i < deep; i++) {
for (let j = 0; j < width; j++) {
if (!(i === 0 && j === 0)) {
if (i === 0) {
grid[i][j] = grid[i][j] + grid[i][j - 1];
} else if (j === 0) {
grid[i][j] = grid[i][j] + grid[i - 1][j];
} else {
grid[i][j] = grid[i][j] + Math.max(grid[i][j - 1], grid[i - 1][j]);
}
}
}
}
return grid[deep - 1][width - 1];
}