题目序号
- 1. leetcode144 二叉树的前序遍历
- 2. leetcode94 二叉树的中序遍历
- 3. leetcode145 二叉树的后序遍历
- 4. leetcode102 二叉树的层序遍历
- 5. leetcode107 二叉树的层序遍历II
- 6. leetcode104 二叉树的最大深度
- 7. leetcode543 二叉树的直径
- 8. leetcode110 平衡二叉树
- 9. leetcode111 二叉树的最小深度
- 10. leetcode404 左叶子之和
- 11. leetcode103 二叉树的锯齿形层序遍历
- 12. leetcode515 在每个树行中找最大值
- 13. leetcode199 二叉树的右视图
- 14. leetcode100 相同的树
- 15. leetcode101 对称二叉树
- 16. leetcode662 二叉树最大宽度
- 17. leetcode222. 完全二叉树的节点个数
- 18. leetcode114. 二叉树展开为链表
- 19. leetcode236 二叉树的最近公共祖先
1. leetcode144 二叉树的前序遍历
2. leetcode94 二叉树的中序遍历
3. leetcode145 二叉树的后序遍历
4. leetcode102 二叉树的层序遍历
5. leetcode107 二叉树的层序遍历II
6. leetcode104 二叉树的最大深度
7. leetcode543 二叉树的直径
8. leetcode110 平衡二叉树
9. leetcode111 二叉树的最小深度
10. leetcode404 左叶子之和
解法一:前序遍历
class Solution {
private int sum = 0;
public int sumOfLeftLeaves(TreeNode root) {
preOrder(root, root);
return sum;
}
private void preOrder(TreeNode node, TreeNode parent){
if(node == null)
return;
//判断其为左叶子节点
if(node.left == null && node.right == null && parent.left == node){
sum += node.val;
}
preOrder(node.left, node);
preOrder(node.right, node);
}
}
解法二:后序遍历
class Solution {
public int sumOfLeftLeaves(TreeNode root) {
return postOrder(root, root);
}
private int postOrder(TreeNode node, TreeNode parent){
if(node == null)
return 0;
if(node.left == null && node.right == null && parent.left == node){
return node.val;
}
int left = postOrder(node.left, node);
int right = postOrder(node.right, node);
return left + right;
}
}
解法三:层序遍历(左、右叶子节点都不需要加入到队列中)
class Solution {
public int sumOfLeftLeaves(TreeNode root) {
if(root == null)
return 0;
int sum = 0;
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
while(!queue.isEmpty()){
TreeNode node = queue.poll();
if (node.left != null) {
//如果是左叶子节点,则将其值累加到结果集中,不需要加入到队列中
if (isLeafNode(node.left)) {
sum += node.left.val;
} else {
//否则加入到队列中
queue.offer(node.left);
}
}
//如果右节点不为空并且不是右叶子节点则将其加入到队列中
if (node.right != null && !isLeafNode(node.right))
queue.offer(node.right);
}
return sum;
}
//判断该节点是否是叶子节点
private boolean isLeafNode(TreeNode node){
return node.left == null && node.right == null;
}
}
11. leetcode103 二叉树的锯齿形层序遍历
解法一:层序遍历(奇数层尾插记录值,偶数层头插记录值)
class Solution {
public List<List<Integer>> zigzagLevelOrder(TreeNode root) {
List<List<Integer>> res = new ArrayList<>();
if(root == null)
return res;
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
//标记层数
int level = 1;
while(!queue.isEmpty()){
int size = queue.size();
//如果是奇数层,则为从左到右;否则从右到左
boolean leftToRight = level % 2 == 1;
LinkedList<Integer> levelNodes = new LinkedList<>();
for(int i = 0; i < size; i++){
TreeNode node = queue.poll();
if(leftToRight){
//从左到右,尾插
levelNodes.addLast(node.val);
}else{
//从右到左,头插
levelNodes.addFirst(node.val);
}
if(node.left != null)
queue.offer(node.left);
if(node.right != null)
queue.offer(node.right);
}
res.add(levelNodes);
level++;
}
return res;
}
}
解法一优化:层序遍历(使用静态数组存储每一层的值,使用一个boolean值来代替层数计算其从左往右还是从右往左)
class Solution {
public List<List<Integer>> zigzagLevelOrder(TreeNode root) {
List<List<Integer>> res = new ArrayList<>();
if(root == null)
return res;
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
//int level = 1;
boolean leftToRight = true;
while(!queue.isEmpty()){
int size = queue.size();
//boolean leftToRight = level % 2 == 1;
//LinkedList<Integer> levelNodes = new LinkedList<>();
Integer[] levelNodes = new Integer[size];
for(int i = 0; i < size; i++){
TreeNode node = queue.poll();
if(leftToRight){
//levelNodes.addLast(node.val);
levelNodes[i] = node.val;
}else{
//levelNodes.addFirst(node.val);
levelNodes[size - 1 - i] = node.val;
}
if(node.left != null)
queue.offer(node.left);
if(node.right != null)
queue.offer(node.right);
}
res.add(Arrays.asList(levelNodes));
leftToRight = !leftToRight;
}
return res;
}
}
12. leetcode515 在每个树行中找最大值
解法一:层序遍历
class Solution {
public List<Integer> largestValues(TreeNode root) {
List<Integer> res = new ArrayList<>();
if(root == null)
return res;
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
while(!queue.isEmpty()){
int size = queue.size();
//记录每一层的最大值
int MaxValue = Integer.MIN_VALUE;
for(int i = 0;i < size; i++){
TreeNode node = queue.poll();
//将每一层的值进行对比取其最大值
MaxValue = Math.max(MaxValue, node.val);
if(node.left != null)
queue.offer(node.left);
if(node.right != null)
queue.offer(node.right);
}
//将该层的最大值加入结果集中
res.add(MaxValue);
}
return res;
}
}
解法二:递归实现
class Solution {
public List<Integer> largestValues(TreeNode root) {
List<Integer> res = new ArrayList<>();
preOrder(root, 0, res);
return res;
}
private void preOrder(TreeNode node, int curLevel, List<Integer> res){
if(node == null)
return;
if(res.size() == curLevel){
//当前层第一个节点,加入到结果集中
res.add(node.val);
}else{
//每次将结果集中的值与当前节点的值作比较,取较大值
int maxValue = Math.max(res.get(curLevel), node.val);
//修改结果集中的最大值
res.set(curLevel, maxValue);
}
preOrder(node.left, curLevel + 1, res);
preOrder(node.right, curLevel + 1, res);
}
}
13. leetcode199 二叉树的右视图
解法一:层序遍历(找到每一层的最后一个节点并将其加入结果集中)
class Solution {
public List<Integer> rightSideView(TreeNode root) {
List<Integer> res = new ArrayList<>();
if(root == null)
return res;
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
while(!queue.isEmpty()){
int size = queue.size();
for(int i = 0; i < size; i++){
TreeNode node = queue.poll();
//该层的最后一个节点即为右视图所看到的节点
if(i == size - 1){
res.add(node.val);
}
if(node.left != null)
queue.offer(node.left);
if(node.right != null)
queue.offer(node.right);
}
}
return res;
}
}
解法二:递归实现(仿照前序遍历,但先遍历右,再遍历左,因此每一层第一个访问的节点即为右视图所看到的节点)
class Solution {
public List<Integer> rightSideView(TreeNode root) {
List<Integer> res = new ArrayList<>();
dfs(root, 0, res);
return res;
}
private void dfs(TreeNode node, int curLevel, List<Integer> res){
if(node == null)
return;
//每一层第一个访问到的节点即为右视图所看到的节点
if(res.size() == curLevel){
res.add(node.val);
}
dfs(node.right, curLevel + 1, res);
dfs(node.left, curLevel + 1, res);
}
}
14. leetcode100 相同的树
解法一:递归实现
class Solution {
public boolean isSameTree(TreeNode p, TreeNode q) {
//如果p为空并且q为空,则是相同的树
if(p == null && q == null)
return true;
//如果p为空q不为空 or p不为空q为空,则不是相同的树
if(p == null || q == null)
return false;
//如果p和q的值不相等,则不是相同的树
if(p.val != q.val)
return false;
//递归判断其左子树和右子树,只有左右子树都相同时才是相同的树
return isSameTree(p.left, q.left) && isSameTree(p.right, q.right);
}
}
解法二:层序遍历
class Solution {
public boolean isSameTree(TreeNode p, TreeNode q) {
if(p == null && q == null)
return true;
if(p == null || q == null)
return false;
Queue<TreeNode> queue1 = new LinkedList<>();
Queue<TreeNode> queue2 = new LinkedList<>();
queue1.offer(p);
queue2.offer(q);
while(!queue1.isEmpty() && !queue2.isEmpty()){
TreeNode node1 = queue1.poll();
TreeNode node2 = queue2.poll();
//如果node1的值不等于node2的值,直接返回false
if(node1.val != node2.val)
return false;
TreeNode left1 = node1.left;
TreeNode right1 = node1.right;
TreeNode left2 = node2.left;
TreeNode right2 = node2.right;
//异或:相同返回false,不同返回true
//如果left1为空left2不为空 or left1不为空left2为空,则直接返回false
if(left1 == null ^ left2 == null)
return false;
//如果right1为空right2不为空 or right1不为空right2为空,则直接返回false
if(right1 == null ^ right2 == null)
return false;
if(left1 != null) queue1.offer(left1);
if(right1 != null) queue1.offer(right1);
if(left2 != null) queue2.offer(left2);
if(right2 != null) queue2.offer(right2);
}
//只有两个队列都为空时,才是相同的树
return queue1.isEmpty() && queue2.isEmpty();
}
}
15. leetcode101 对称二叉树
解法一:递归实现
class Solution {
public boolean isSymmetric(TreeNode root) {
if(root == null)
return true;
return isMirror(root.left, root.right);
}
//判断两棵树是否是镜像
private boolean isMirror(TreeNode t1, TreeNode t2){
if(t1 == null && t2 == null)
return true;
if(t1 == null || t2 == null)
return false;
if(t1.val != t2.val)
return false;
return isMirror(t1.left, t2.right) && isMirror(t1.right, t2.left);
}
}
解法二:层序遍历
class Solution {
public boolean isSymmetric(TreeNode root) {
if(root == null || root.left == null && root.right == null)
return true;
Queue<TreeNode> queue = new LinkedList<>();
//将根节点的左节点入队
queue.offer(root.left);
//将根节点的右节点入队
queue.offer(root.right);
while(!queue.isEmpty()){
TreeNode left = queue.poll();
TreeNode right = queue.poll();
//如果都为空则跳出当前循环
if(left == null && right == null)
continue;
//如果有一个为空,则返回false
if(left == null || right == null)
return false;
//如果两个节点值不相同,则返回false
if(left.val != right.val)
return false;
queue.offer(left.left);
queue.offer(right.right);
queue.offer(left.right);
queue.offer(right.left);
}
return queue.isEmpty();
}
}
16. leetcode662 二叉树最大宽度
解法一:BFS层序遍历,给每一层节点标记序号
class Solution {
class Node{
int treeNodeNum;
TreeNode treeNode;
public Node(TreeNode treeNode, int treeNodeNum){
this.treeNode = treeNode;
this.treeNodeNum = treeNodeNum;
}
}
public int widthOfBinaryTree(TreeNode root) {
if(root == null)
return 0;
Queue<Node> queue = new LinkedList<>();
queue.offer(new Node(root, 1));
int maxWidth = 0;
while(!queue.isEmpty()){
int size = queue.size();
int startNum = 0;
int endNum = 0;
for(int i = 0; i < size; i++){
Node curNode = queue.poll();
TreeNode treeNode = curNode.treeNode;
int treeNodeNum = curNode.treeNodeNum;
//i == 0表示该层第一个节点,即该层最左非空节点
if(i == 0){
startNum = treeNodeNum;
}
//i == size - 1表示该层最后一个节点,即该层最右非空节点
if(i == size - 1){
endNum = treeNodeNum;
}
if(treeNode.left != null){
queue.offer(new Node(treeNode.left, treeNodeNum * 2));
}
if(treeNode.right != null){
queue.offer(new Node(treeNode.right, treeNodeNum * 2 + 1));
}
}
maxWidth = Math.max(maxWidth, endNum - startNum + 1);
}
return maxWidth;
}
}
解法二:dfs前序遍历初始化该层节点start + end编号,后序遍历向上返回最大宽带
class Solution {
public int widthOfBinaryTree(TreeNode root) {
return dfs(root, 0, 1, new ArrayList(), new ArrayList());
}
private int dfs(TreeNode root, int level, int treeNodeNum, List<Integer> start, List<Integer> end){
if(root == null)
return 0;
//前序
if(start.size() == level){ //该层第一个节点
start.add(treeNodeNum);
end.add(treeNodeNum);
}else{
end.set(level, treeNodeNum);
}
int leftMaxWidth = dfs(root.left, level + 1, 2 * treeNodeNum, start, end);
int rightMaxWidth = dfs(root.right, level + 1, 2 * treeNodeNum + 1, start, end);
//后序
int curWidth = end.get(level) - start.get(level) + 1;
return Math.max(curWidth, Math.max(leftMaxWidth, rightMaxWidth));
}
}
17. leetcode222. 完全二叉树的节点个数
解法一:dfs后序遍历,时间复杂度为O(n)
class Solution {
public int countNodes(TreeNode root) {
if(root == null)
return 0;
int left = countNodes(root.left);
int right = countNodes(root.right);
return left + right + 1;
}
}
解法二:二分查找 + 位运算,时间复杂度为O(log²n)
规定根节点位于第
0
层,完全二叉树的最大层数为h
。根据完全二叉树的特性可知,完全二叉树的最左边的节点一定位于最底层,因此从根节点出发,每次访问左子节点,直到遇到叶子节点,该叶子节点即为完全二叉树的最左边的节点,经过的路径长度即为最大层数h
。
class Solution {
public int countNodes(TreeNode root) {
if(root == null)
return 0;
//1. 计算完全二叉树的层数
// 层数是从0开始,根节点为第0层
int level = 0;
TreeNode node = root;
while(node.left != null){
level++;
node = node.left;
}
//2. 二分查找
// 完全二叉树的节点数的范围:[2 ^ level, 2 ^ (level + 1) - 1]
int low = 1 << level;
int high = (1 << (level + 1)) - 1;
while(low < high){
//需要+1
int mid = low + (high - low + 1) / 2;
if(exists(root, level, mid)){
low = mid;
}else{
high = mid - 1;
}
}
return low;
}
private boolean exists(TreeNode root, int level, int mid){
//mask为倒数第二层第一个节点的值,如上图01000
int mask = 1 << (level - 1);
TreeNode node = root;
while(node != null && mask > 0){
//例如:mask为01000,mid为10010
//mask & mid == 00000,因此向左查找
if((mask & mid) == 0){
node = node.left;
}else{
//例如:mask为01000,mid为11000
//mask & mid == 01000,因此向右查找
node = node.right;
}
//例如:mask为01000,检查根节点到第二层节点
// mask >>= 1 后 mask = 00100,检查第二层节点到第三层节点
mask >>= 1;
}
return node != null;
}
}
18. leetcode114. 二叉树展开为链表
解法一:先前序遍历再串联链表
class Solution {
public void flatten(TreeNode root) {
List<TreeNode> list = new ArrayList<>();
preOrder(root, list);
for(int i = 1; i < list.size(); i++){
TreeNode prev = list.get(i - 1);
TreeNode curr = list.get(i);
prev.left = null;
prev.right = curr;
}
}
private void preOrder(TreeNode root, List<TreeNode> list){
if(root == null)
return;
list.add(root);
preOrder(root.left, list);
preOrder(root.right, list);
}
}
解法二:边遍历边串联(前序遍历非递归实现)
class Solution {
public void flatten(TreeNode root) {
if(root == null)
return;
Deque<TreeNode> stack = new ArrayDeque<>();
stack.push(root);
//指向前一个节点
TreeNode prev = null;
while(!stack.isEmpty()){
//指向当前节点
TreeNode curr = stack.pop();
if(prev != null){
prev.left = null;
prev.right = curr;
}
if(curr.right != null){
stack.push(curr.right);
}
if(curr.left != null){
stack.push(curr.left);
}
prev = curr;
}
}
}
解法三:原地改变指针
class Solution {
public void flatten(TreeNode root) {
if(root == null)
return;
TreeNode curr = root;
while(curr != null){
//如果当前节点的左子树不为空,则去左子树中查找右子树的前继届点
if(curr.left != null){
//记录当前左子树节点
TreeNode left = curr.left;
//pre用来标识当前节点左子树中的最右节点
TreeNode pre = left;
//寻找左子树的最右节点,也就是根节点右子树的前节点
while(pre.right != null){
pre = pre.right;
}
pre.right = curr.right;
curr.left = null;
curr.right = left;
}
curr = curr.right;
}
}
}
19. leetcode236 二叉树的最近公共祖先
解法一:维护节点和父亲节点的关系
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
//1. 维护子节点与其对应父节点的关系
Map<Integer, TreeNode> parent = new HashMap<>();
dfs(root, parent);
//2. 从p节点开始依次访问其祖先
Set<Integer> visited = new HashSet<>();
while(p != null){
visited.add(p.val);
p = parent.get(p.val);
}
//3. 从节点q开始,依次访问其祖先
// 如果第一次遇到了p的祖先,那就是最近公共祖先
while(q != null){
if(visited.contains(q.val)){
return q;
}
q = parent.get(q.val);
}
return null;
}
private void dfs(TreeNode node, Map<Integer, TreeNode> parent){
if(node == null)
return;
if(node.left != null)
parent.put(node.left.val, node);
if(node.right != null)
parent.put(node.right.val, node);
dfs(node.left, parent);
dfs(node.right, parent);
}
}
解法二:dfs后序遍历
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(root == null || root == p || root == q){
return root;
}
TreeNode left = lowestCommonAncestor(root.left, p, q);
TreeNode right = lowestCommonAncestor(root.right, p, q);
if(left == null && right == null)
return null;
if(left == null)
return right;
if(right == null)
return left;
return root;
}
}