本系列为笔者的 Leetcode 刷题记录,顺序为 Hot 100 题官方顺序,根据标签命名,记录笔者总结的做题思路,附部分代码解释和疑问解答,01~07为C++语言,08及以后为Java语言。
01 二叉树的中序遍历


java
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
}
}
方法一:递归
java
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
inoder(root, res);
return res;
}
public void inoder(TreeNode root, List<Integer> res){
if(root == null){
return;
}
//中序遍历
inoder(root.left, res);
res.add(root.val);
inoder(root.right, res);
}
}
如果一个方法的返回值是int
,那么调用这个方法的时候可以不写一个整数来接收int值,而是直接调用该方法吗?
是的!你完全可以直接调用一个返回值为 int
的方法,而不接收它返回的值**,编译和运行都不会报错,但具体是否这么写,取决于你有没有用到这个**返回值。
方法二:栈
java
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
Deque<TreeNode> stk = new LinkedList<>();
while(root != null || !stk.isEmpty()){
while(root != null){
stk.push(root); //压栈
root = root.left;
}
root = stk.pop(); //弹栈
res.add(root.val);
root = root.right;
}
return res;
}
}
方法三:Morris 中序遍历

java
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
TreeNode pre = null;
while(root != null){
if(root.left != null){
//1.寻找pre
pre = root.left;
while(pre.right != null && pre.right != root){
pre = pre.right;
}
//2.判断pre.right
if(pre.right == null){
pre.right = root;
root = root.left; //建链,左移
}else{
res.add(root.val);
pre.right = null;
root = root.right; //断链,右移
}
}else{
res.add(root.val);
root = root.right;
}
}
return res;
}
}
为什么要进行pre.right = null;
的断链处理?
pre.right = null;
的断链处理是为了恢复树的原始结构。这个算法使用了Morris中序遍历,它利用树中的空闲右指针来建立链接,从而避免使用额外的栈空间。
02 二叉树的最大深度


java
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public int maxDepth(TreeNode root) {
}
}
方法一:递归
java
class Solution {
public int maxDepth(TreeNode root) {
if(root == null){
return 0;
}
int leftHeight = maxDepth(root.left);
int rightHeight = maxDepth(root.right);
return Math.max(leftHeight, rightHeight) + 1;
}
}
Math.max
啥意思?
Math.max
是 Java 中 Math
类的一个静态方法,它用于返回两个给定数中的最大值。
方法二:广度优先搜索
java
class Solution {
public int maxDepth(TreeNode root) {
if(root == null){
return 0;
}
//广度优先遍历 queue
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
int answer = 0;
while(!queue.isEmpty()){
//a.获取该行长度
int size = queue.size();
while(size > 0){
//b.遍历该行所有结点,添加所有孩子结点
TreeNode node = queue.poll();
if(node.left != null){
queue.offer(node.left);
}
if(node.right != null){
queue.offer(node.right);
}
size--;
}
//c.每遍历一行,answer加一
answer++;
}
return answer;
}
}
03 翻转二叉树


java
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public TreeNode invertTree(TreeNode root) {
}
}
方法一:递归
java
class Solution {
public TreeNode invertTree(TreeNode root) {
//0.特殊情况判断
if(root == null){
return root;
}
//1.获取左右孩子指针
TreeNode left = invertTree(root.left);
TreeNode right = invertTree(root.right);
//2.交换左右孩子指针
root.left = right;
root.right = left;
return root;
}
}
04 对称二叉树


java
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public boolean isSymmetric(TreeNode root) {
}
}
方法一:递归
java
class Solution {
public boolean isSymmetric(TreeNode root) {
if (root == null) {
return true;
}
return check(root.left, root.right);
}
public boolean check(TreeNode p, TreeNode q){
if(p == null && q == null){
return true;
}
if(p == null || q == null){
return false;
}
return p.val == q.val && check(p.left, q.right) && check(p.right, q.left);
}
}
① 如果TreeNode root
为null
咋办,根本就没有root.left
和root.right
吧?
如果 root
为 null
,那么传递给 check(root.left, root.right)
的参数就是 check(null, null)
。
② 为什么if(p == null && q == null)
之后直接return true;
,万一还有别的结点没有检查呢,直接就返回正确吗?
当递归到底叶子节点时,不存在还未检查的节点,因为递归调用本身会遍历所有对应的节点对。
方法二:队列
java
class Solution {
public boolean isSymmetric(TreeNode root) {
return check(root, root);
}
public boolean check(TreeNode u, TreeNode v){
//1.创建并加入队列,头结点
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(u);
queue.offer(v);
while(!queue.isEmpty()){
//2.移出队列,判断结点状况
u = queue.poll();
v = queue.poll();
if(u == null && v == null){
continue;
}
if((u == null || v == null) || u.val != v.val){
return false;
}
//3.加入队列,左右孩子结点
queue.offer(u.left);
queue.offer(v.right);
queue.offer(u.right);
queue.offer(v.left);
}
return true;
}
}
为什么u == null && v == null
成立要进行continue
,而不是直接返回true
?
如果 u == null && v == null
,这意味着当前的两个节点都是空的,但这只是树的一部分,整体是否对称还需要继续检查其他节点,只有在所有节点都已经处理并且没有发现不对称时,才会返回 true
。
05 二叉树的直径


java
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public int diameterOfBinaryTree(TreeNode root) {
}
}
方法一:递归
java
class Solution {
int ans = 0;
public int diameterOfBinaryTree(TreeNode root) {
depth(root);
return ans-1;
}
public int depth(TreeNode root){
if(root == null){
return 0;
}
int L = depth(root.left);
int R = depth(root.right);
ans = Math.max(ans, L + R + 1);
return Math.max(L, R) + 1;
}
}