📢博客主页:🏀敲代码的布莱恩特🏀 📢欢迎点赞 👍 收藏 ?留言 📝 欢迎讨论!👏 📢本文由 【敲代码的布莱恩特】 原创,首发于 CSDN🙉🙉🙉 📢由于博主是在学小白一枚,难免会有错误,有任何问题欢迎评论区留言指出,感激不尽!? 📖精品专栏(不定时更新)【JavaSE】 【Java数据结构】【LeetCode】
【Java数据结构】二叉树进阶——非递归实现前中后序遍历二叉树+进阶大厂面试题
🗽非递归实现遍历二叉树(深入理解二叉树)
- 代码每行都有注释,可以一步一步的画着图走一走,多走几遍,理解会上一个档次!
- 前序遍历和中序遍历都用到栈,代码可以说一模一样,只不过打印节点的时机不一样
?非递归前序遍历
public void FDG_reOrderTraversal(TreeNode root){
if (root == null) {
return;
}
TreeNode cur = root;
Stack<TreeNode> stack = new Stack<TreeNode>();
while(cur != null || !stack.isEmpty()) {
while (cur != null) {
stack.push(cur);
System.out.print(cur.value+" ");
cur = cur.left;
}
TreeNode top = stack.pop();
cur = top.right;
}
System.out.println();
}
?非递归中序遍历
public void FDG_inOrderTraversal(TreeNode root) {
if (root == null) {
return;
}
TreeNode cur = root;
Stack<TreeNode> stack = new Stack<TreeNode>();
while(cur != null || !stack.isEmpty()) {
while (cur != null) {
stack.push(cur);
cur = cur.left;
}
TreeNode top = stack.pop();
System.out.print(top.value+" ");
cur = top.right;
}
System.out.println();
}
?非递归后序遍历
public void postOrderTraversalNor(TreeNode root) {
if(root == null) return;
TreeNode cur = root;
Stack<TreeNode> stack = new Stack<>();
TreeNode pre = null;
while (cur != null || !stack.empty()) {
while (cur != null) {
stack.push(cur);
cur = cur.left;
}
cur = stack.peek();
if (cur.right == null || cur.right == pre) {
TreeNode popNode = stack.pop();
System.out.print(popNode.value + " ");
pre = cur;
cur = null;
} else {
cur = cur.right;
}
}
System.out.println();
}
🗽大厂OJ面试题
🎄1. 二叉树的构建及遍历
题目:
思路:
- 本题思路很简单,就是遍历字符串,因为这是根据前序遍历搞出来的字符串
- 所以构建二叉树,也要根据这个 根->左节点->右节点 的顺序来构建
实现代码:
import java.util.*;
class TreeNode{
char value;
TreeNode left;
TreeNode right;
public TreeNode(char value){
this.value = value;
}
}
public class Main{
public static void main(String[]args){
Scanner scn = new Scanner(System.in);
String str = scn.nextLine();
TreeNode root = creatTree(str);
inOrderTraveled(root);
}
public static int i = 0;
public static TreeNode creatTree(String str){
if(str==null){
return null;
}
TreeNode root = null;
if(str.charAt(i)!='#'){
root = new TreeNode(str.charAt(i));
i++;
root.left = creatTree(str);
root.right = creatTree(str);
}else{
i++;
}
return root;
}
public static void inOrderTraveled(TreeNode root){
if(root==null) return;
inOrderTraveled(root.left);
System.out.print(root.value+" ");
inOrderTraveled(root.right);
}
}
🎄2. 二叉树的分层遍历
题目:
思路:
-
层序遍历就是一层一层的遍历节点 -
这题还有一个要求就是,输出的时候将一层的节点放在一行,下一层的节点放在下一行,这就需要用到一个二维数组 来储存每一层的节点 -
我们先来观察一下 层序遍历的过程中,结点进队列和出队列的过程: 请看图 -
可是如何知道当前访问到的节点是哪一层的呢? 截取 BFS 遍历过程中的某个时刻: 可以看到,此时队列中的结点是 3、4、5,分别来自第 1 层和第 2 层。这个时候,第 1 层的结点还没出完,第 2 层的结点就进来了 ,而且两层的结点在队列中紧挨在一起,我们无法区分队列中的结点来自哪一层 。 因此,我们在每一层遍历开始前,先记录队列中的结点数量 n(也就是这一层的结点数量),然后一口气处理完这一层的 n 个结点。
实现代码:
class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> list = new ArrayList();
Queue<TreeNode> queue = new LinkedList<>();
if (root==null){
return list;
}
queue.offer(root);
while(!queue.isEmpty()) {
int n = queue.size();
List<Integer> level = new ArrayList();
for(int i = 0 ; i<n ; i++){
TreeNode top = queue.poll();
level.add(top.val);
if (top.left != null) {
queue.offer(top.left);
}
if (top.right != null) {
queue.offer(top.right);
}
}
list.add(level);
}
return list;
}
}
🎄3. 给定一个二叉树,找到该树中两个指定节点的最近公共祖先
题目:
思路:
-
祖先的定义: 若节点 p 在节点 root 的左(右)子树中,或 p = root ,则称 root 是 p 的祖先。 -
根据以上定义,若 root 是 p,q 的 最近公共祖先 ,则只可能为以下情况之一: ①p 和 q 在 root的子树中,且分列 root 的 异侧(即分别在左、右子树中); ②p = root ,且 q 在 root 的左或右子树中; ③q = root ,且 p 在 root 的左或右子树中; 考虑通过递归对二叉树进行先序遍历,当遇到节点 p 或 q 时返回。从底至顶回溯,当节点 p,q 在节点 root的异侧时,节点 root 即为最近公共祖先,则向上返回 root 。
实现代码:
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(root==null) return null;
if(root==p || root == q) return root;
TreeNode leftTree = lowestCommonAncestor(root.left,p,q);
TreeNode rightTree = lowestCommonAncestor(root.right,p,q);
if(leftTree!=null && rightTree!=null){
return root;
}
if(leftTree!=null){
return leftTree;
}
if(rightTree!=null){
return rightTree;
}
return null;
}
}
🎄4. 二叉树搜索树转换成排序双向链表
题目:
思路:
- 已知将二叉搜索树进行中序遍历可以得到
由小到大的顺序排列 ,因此本题最直接的想法就是进行中序遍历 。 - 根据题目的要求1,不能创建新的结点,所以我们
设置一个pre用于指向前驱节点 例如root为指向10的时候,preNode指向8,如图所示:
实现代码:
public class Solution {
public TreeNode pre = null;
public void ConvertChild(TreeNode pcur) {
if(pcur==null){
return;
}
ConvertChild(pcur.left);
pcur.left=pre;
if(pre!=null){
pre.right=pcur;
}
pre=pcur;
ConvertChild(pcur.right);
}
public TreeNode Convert(TreeNode pRootOfTree) {
if(pRootOfTree==null) return null;
ConvertChild(pRootOfTree);
TreeNode head = pRootOfTree;
while(head.left!=null){
head=head.left;
}
return head;
}
}
🎄5. 根据一棵树的前序遍历与中序遍历构造二叉树
题目:
思路:
-
所以我们只需要根据先序遍历得到根节点,然后在中序遍历中找到根节点的位置,它的左边就是左子树的节点,右边就是右子树的节点。 -
递归生成左子树和右子树
实现代码:
class Solution {
public int preindex = 0;
public TreeNode buildTreeChild(int[] preorder,int[] inorder,int inbegin,int inend) {
if(inbegin > inend) {
return null;
}
TreeNode root = new TreeNode(preorder[preindex]);
int rootIndex = findRootIndex(inorder,inbegin,inend,preorder[preindex]);
preindex++;
root.left = buildTreeChild(preorder,inorder,inbegin,rootIndex-1);
root.right = buildTreeChild(preorder,inorder,rootIndex+1,inend);
return root;
}
public int findRootIndex(int[] inorder,int inbegin,int inend,int key) {
for(int i = inbegin;i <= inend;i++) {
if(inorder[i] == key) {
return i;
}
}
return -1;
}
public TreeNode buildTree(int[] preorder, int[] inorder) {
if(preorder == null || inorder == null) return null;
return buildTreeChild(preorder,inorder,0,inorder.length-1);
}
}
🎄6. 根据一棵树的中序遍历和后序遍历构造二叉树
题目:
思路:
- 和上题几乎一样,只需要
几处小改动 - 因为是给的是
后续遍历 ,所以构建的时候,读取后续遍历数组要从后往前读取 ,并且构建的时候是 根->右->左
实现代码:
class Solution {
public int postindex = 0;
public TreeNode buildTreeChild(int[] postorder,int[] inorder,int inbegin,int inend) {
if(inbegin > inend) {
return null;
}
TreeNode root = new TreeNode(postorder[postindex]);
int rootIndex = findRootIndex(inorder,inbegin,inend,postorder[postindex]);
postindex--;
root.right = buildTreeChild(postorder,inorder,rootIndex+1,inend);
root.left = buildTreeChild(postorder,inorder,inbegin,rootIndex-1);
return root;
}
public int findRootIndex(int[] inorder,int inbegin,int inend,int key) {
for(int i = inbegin;i <= inend;i++) {
if(inorder[i] == key) {
return i;
}
}
return -1;
}
public TreeNode buildTree(int[] inorder, int[] postorder) {
postindex = postorder.length-1;
if(postorder == null || inorder == null) return null;
return buildTreeChild(postorder,inorder,0,inorder.length-1);
}
}
🎄7. 二叉树创建字符串
题目:
思路:
- 我们可以使用递归的方法得到二叉树的前序遍历。在递归时,根据题目描述,我们需要加上额外的括号,会有以下 4 种情况:
① 如果当前节点有两个孩子 ,那我们在递归时,需要在两个孩子的结果外都加上一层括号; ②如果当前节点没有孩子 ,那我们不需要在节点后面加上任何括号 ; ③如果当前节点只有左孩子 ,那我们在递归时,只需要在左孩子的结果外加上一层括号,而不需要给右孩子加上任何括号 ; ④如果当前节点只有右孩子 ,那我们在递归时,需要先加上一层空的括号 () 表示左孩子为空 ,再对右孩子进行递归,并在结果外加上一层括号。
考虑完上面的 4 种情况,我们就可以得到最终的字符串。
实现代码:
class Solution {
public void tree2strChild(TreeNode root,StringBuilder sb) {
if(root == null) return ;
sb.append(root.val);
if(root.left==null){
if(root.right==null){
return;
}else{
sb.append("()");
}
}else{
sb.append("(");
tree2strChild(root.left,sb);
sb.append(")");
}
if(root.right==null){
return;
}else{
sb.append("(");
tree2strChild(root.right,sb);
sb.append(")");
}
}
public String tree2str(TreeNode root) {
if(root==null) return null;
StringBuilder sb = new StringBuilder();
tree2strChild(root,sb);
return sb.toString();
}
}
🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙 ????????原创不易,如有错误,欢迎评论区留言指出,感激不尽? ???????????????????????如果觉得内容不错,给个三连不过分吧~ ?????? ? ????????????????????????????????????看到会回访~ ??????????????? ???????????????????? ? 🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙
|