日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

数据结构 - 二叉树 - 面试中常见的二叉树算法题

發布時間:2024/2/28 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 数据结构 - 二叉树 - 面试中常见的二叉树算法题 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

數據結構 - 二叉樹 - 面試中常見的二叉樹算法題

數據結構是面試中必定考查的知識點,面試者需要掌握幾種經典的數據結構:線性表(數組、鏈表)、棧與隊列(二叉樹、二叉查找樹、平衡二叉樹、紅黑樹)、

本文主要介紹中的常見的二叉樹數據結構。包括

  • 概念簡介
  • 二叉樹中樹節點的數據結構(Java)
  • 二叉樹的遍歷(Java)
  • 常見的二叉樹算法題(Java)

概念簡介

如果對二叉樹概念已經基本掌握,可以跳過該部分,直接查看常見鏈表算法題。

二叉樹基本概念

二叉樹在圖論中是這樣定義的:二叉樹是一個連通的無環圖,并且每一個頂點的度不大于3。有根二叉樹還要滿足根結點的度不大于2。有了根結點之后,每個頂點定義了唯一的父結點,和最多2個子結點。二叉樹性質如下:

  • 二叉樹的每個結點至多只有二棵子樹(不存在度大于2的結點),二叉樹的子樹有左右之分,次序不能顛倒。
  • 二叉樹的第 i 層至多有 2i?1 個結點。
  • 深度為 k 的二叉樹至多有 2k?1 個結點。
  • 對任何一棵二叉樹T,如果其終端結點數為n0,度為2的結點數為n2,則n0=n2+1
  • 一棵深度為k,且有 2k?1 個節點稱之為滿二叉樹
  • 深度為k,有n個節點的二叉樹,當且僅當其每一個節點都與深度為k的滿二叉樹中,序號為1至n的節點對應時,稱之為完全二叉樹
  • 平衡二叉樹又被稱為AVL樹(區別于AVL算法),它是一棵二叉排序樹,且具有以下性質:它是一棵空樹或它的左右兩個子樹的高度差的絕對值不超過1,并且左右兩個子樹都是一棵平衡二叉樹。


二叉樹中樹節點的數據結構

二叉樹由一系列樹結點組成,每個結點包括三個部分:一個是存儲數據元素的數據域,另一個是存儲左子結點地址的指針域,另一個是存儲右子結點地址的指針域。

定義樹節點為類:TreeNode。具體實現如下:

public class TreeNode {public int val; // 數據域public TreeNode left; // 左子樹根節點public TreeNode right; // 右子樹根節點public TreeNode() {}public TreeNode(int val) {this.val = val;}}

二叉樹的遍歷

1. 前序遍歷

遞歸解法

  • 如果二叉樹為空,空操作
  • 如果二叉樹不為空,訪問根節點,前序遍歷左子樹,前序遍歷右子樹
/*** 1. 前序遍歷* 遞歸* @param root 樹根節點*/ public static void preorderTraversalRec(TreeNode root){if (root == null) {return;}System.out.print(root.val + "->");preorderTraversalRec(root.left);preorderTraversalRec(root.right); }

非遞歸解法:用一個輔助stack,總是先把右孩子放進棧。

/*** 1. 前序遍歷* 非遞歸* @param root 樹根節點*/ public static void preorderTraversal2(TreeNode root) {if (root == null) {return;}Stack<TreeNode> stack = new Stack<>(); // 輔助棧TreeNode cur = root;while (cur != null || !stack.isEmpty()) {while (cur != null) { // 不斷將左子節點入棧,直到cur為空stack.push(cur);System.out.print(cur.val + "->"); // 前序遍歷,先打印當前節點在打印左子節點,然后再把右子節點加到棧中cur = cur.left;}if (!stack.isEmpty()) { // 棧不為空,彈出棧元素cur = stack.pop(); // 此時彈出最左邊的節點cur = cur.right; // 令當前節點為右子節點}} }/*** 1. 前序遍歷* 非遞歸解法2* @param root 樹根節點*/ public static void preorderTraversal(TreeNode root) {if (root == null) {return;}Stack<TreeNode> stack = new Stack<>(); // 輔助棧保存樹節點stack.add(root);while (!stack.isEmpty()) { // 棧不為空TreeNode temp = stack.pop();System.out.print(temp.val + "->"); // 先根節點,因為是前序遍歷if (temp.right != null) { // 先添加右孩子,因為棧是先進后出stack.add(temp.right);}if (temp.left != null) {stack.add(temp.left);}} }
2. 中序遍歷

遞歸解法

  • 如果二叉樹為空,空操作
  • 如果二叉樹不為空,中序遍歷左子樹,訪問根節點,中序遍歷右子樹
/*** 2. 中序遍歷* 遞歸* @param root 樹根節點*/ public static void inorderTraversalRec(TreeNode root){if (root == null) {return;}inorderTraversalRec(root.left);System.out.print(root.val + "->");inorderTraversalRec(root.right); }

非遞歸解法:用棧先把根節點的所有左孩子都添加到棧內,然后輸出棧頂元素,再處理棧頂元素的右子樹。

/*** 2. 中序遍歷* 非遞歸* @param root 樹根節點*/ public static void inorderTraversal(TreeNode root) {if (root == null) {return;}Stack<TreeNode> stack = new Stack<>(); // 輔助棧TreeNode cur = root;while (cur != null || !stack.isEmpty()) {while (cur != null) { // 不斷將左子節點入棧,直到cur為空stack.push(cur);cur = cur.left;}if (!stack.isEmpty()) { // 棧不為空,彈出棧元素cur = stack.pop(); // 此時彈出最左邊的節點System.out.print(cur.val + "->"); // 中序遍歷,先打印左子節點在打印當前節點,然后再把右子節點加到棧中cur = cur.right; // 令當前節點為右子節點}} }
3. 后序遍歷

遞歸解法

  • 如果二叉樹為空,空操作
  • 如果二叉樹不為空,后序遍歷左子樹,后序遍歷右子樹,訪問根節點
/*** 3. 后序遍歷* 遞歸* @param root 樹根節點*/ public static void postorderTraversalRec(TreeNode root){if (root == null) {return;}postorderTraversalRec(root.left);postorderTraversalRec(root.right);System.out.print(root.val + "->"); }

非遞歸解法:雙棧法。

/*** 3. 后序遍歷* 非遞歸* @param root 樹根節點*/ public static void postorderTraversal(TreeNode root) {if(root == null) {return;}Stack<TreeNode> stack1 = new Stack<>(); // 保存樹節點Stack<TreeNode> stack2 = new Stack<>(); // 保存后序遍歷的結果stack1.add(root);while (!stack1.isEmpty()) {TreeNode temp = stack1.pop();stack2.push(temp); // 將彈出的元素加到stack2中if (temp.left != null) { // 左子節點先入棧stack1.push(temp.left);}if (temp.right != null) { // 右子節點后入棧stack1.push(temp.right);}}while (!stack2.isEmpty()) {System.out.print(stack2.pop().val + "->");} }
4. 層次遍歷

思路:分層遍歷二叉樹(按層次從上到下,從左到右)迭代,相當于廣度優先搜索,使用隊列實現。隊列初始化,將根節點壓入隊列。當隊列不為空,進行如下操作:彈出一個節點,訪問,若左子節點或右子節點不為空,將其壓入隊列。

/*** 4. 層次遍歷* @param root 根節點*/ public static void levelTraversal(TreeNode root){if(root == null) {return;}Queue<TreeNode> queue = new LinkedList<>(); // 對列保存樹節點queue.add(root);while (!queue.isEmpty()) {TreeNode temp = queue.poll();System.out.print(temp.val + "->");if (temp.left != null) { // 添加左右子節點到對列queue.add(temp.left);}if (temp.right != null) {queue.add(temp.right);}} }

常見的二叉樹算法題

1. 求二叉樹中的節點個數

遞歸解法O(n)

  • 如果二叉樹為空,節點個數為0
  • 如果二叉樹不為空,二叉樹節點個數 = 左子樹節點個數 + 右子樹節點個數 + 1
/*** 1. 求二叉樹中的節點個數* 遞歸* @param root 樹根節點* @return 節點個數*/ public static int getNodeNumRec(TreeNode root) {if (root == null) {return 0;}return getNodeNumRec(root.left) + getNodeNumRec(root.right) + 1; }

非遞歸解法O(n)。基本思想同LevelOrderTraversal。即用一個Queue,在Java里面可以用LinkedList來模擬。

/*** 1. 求二叉樹中的節點個數* 非遞歸* @param root 樹根節點* @return 節點個數*/ public static int getNodeNum(TreeNode root) {if (root == null) {return 0;}Queue<TreeNode> queue = new LinkedList<>(); // 用隊列保存樹節點,先進先出queue.add(root);int count = 1; // 節點數量while (!queue.isEmpty()) {TreeNode temp = queue.poll(); // 每次從對列中刪除節點,并返回該節點信息if (temp.left != null) { // 添加左子孩子到對列queue.add(temp.left);count++;}if (temp.right != null) { // 添加右子孩子到對列queue.add(temp.right);count++;}}return count; }
2. 求二叉樹的深度(高度)

遞歸解法O(n)

  • 如果二叉樹為空,二叉樹的深度為0
  • 如果二叉樹不為空,二叉樹的深度 = max(左子樹深度, 右子樹深度) + 1
/** * 求二叉樹的深度(高度) * 遞歸 * @return 樹的深度 */ public static int getDepthRec(TreeNode root) {if (root == null) {return 0;}return Math.max(getDepthRec(root.left), getDepthRec(root.right)) + 1; }

非遞歸解法O(n)。基本思想同LevelOrderTraversal。即用一個Queue,在Java里面可以用LinkedList來模擬。

/*** 求二叉樹的深度(高度)* 非遞歸* @param root 樹根節點* @return 樹的深度*/ public static int getDepth(TreeNode root) {if (root == null) {return 0;}int currentLevelCount = 1; // 當前層的節點數量int nextLevelCount = 0; // 下一層節點數量int depth = 0; // 樹的深度Queue<TreeNode> queue = new LinkedList<>(); // 對列保存樹節點queue.add(root);while (!queue.isEmpty()) {TreeNode temp = queue.remove(); // 移除節點currentLevelCount--; // 當前層節點數減1if (temp.left != null) { // 添加左節點并更新下一層節點個數queue.add(temp.left);nextLevelCount++;}if (temp.right != null) { // 添加右節點并更新下一層節點個數queue.add(temp.right);nextLevelCount++;}if (currentLevelCount == 0) { // 如果是該層的最后一個節點,樹的深度加1depth++;currentLevelCount = nextLevelCount; // 更新當前層節點數量并且重置下一層節點數量nextLevelCount = 0;}}return depth; }
3. 求二叉樹第k層的節點個數

遞歸解法O(n)

思路:求以root為根的k層節點數目,等價于求以root左孩子為根的k-1層(因為少了root)節點數目 加上以root右孩子為根的k-1層(因為 少了root)節點數目。即:

  • 如果二叉樹為空或者k<1,返回0
  • 如果二叉樹不為空并且k==1,返回1
  • 如果二叉樹不為空且k>1,返回root左子樹中k-1層的節點個數與root右子樹k-1層節點個數之和
/*** 求二叉樹第k層的節點個數* 遞歸* @param root 根節點* @param k 第k個節點* @return 第k層節點數*/ public static int getNodeNumKthLevelRec(TreeNode root, int k) {if (root == null || k < 1) {return 0;}if (k == 1) {return 1;}return getNodeNumKthLevelRec(root.left, k - 1) + getNodeNumKthLevelRec(root.right, k - 1); }
4. 求二叉樹中葉子節點的個數

遞歸解法

  • 如果二叉樹為空,返回0
  • 如果二叉樹是葉子節點,返回1
  • 如果二叉樹不是葉子節點,二叉樹的葉子節點數 = 左子樹葉子節點數 + 右子樹葉子節點數
/*** 4. 求二叉樹中葉子節點的個數* 遞歸* @param root 根節點* @return 葉子節點個數*/ public static int getNodeNumLeafRec(TreeNode root) {if (root == null) {return 0;}if (root.left == null && root.right == null) {return 1;}return getNodeNumLeafRec(root.left) + getNodeNumLeafRec(root.right); }

非遞歸解法:基于層次遍歷進行求解,利用Queue進行。

/*** 4. 求二叉樹中葉子節點的個數(迭代)* 非遞歸* @param root 根節點* @return 葉子節點個數*/ public static int getNodeNumLeaf(TreeNode root){if (root == null) {return 0;}int leaf = 0; // 葉子節點個數Queue<TreeNode> queue = new LinkedList<>();queue.add(root);while (!queue.isEmpty()) {TreeNode temp = queue.poll();if (temp.left == null && temp.right == null) { // 葉子節點leaf++;}if (temp.left != null) {queue.add(temp.left);}if (temp.right != null) {queue.add(temp.right);}}return leaf; }
5. 判斷兩棵二叉樹是否相同的樹

遞歸解法

  • 如果兩棵二叉樹都為空,返回真
  • 如果兩棵二叉樹一棵為空,另外一棵不為空,返回假
  • 如果兩棵二叉樹都不為空,如果對應的左子樹和右子樹都同構返回真,其他返回假
/*** 5. 判斷兩棵二叉樹是否相同的樹。* 遞歸* @param r1 二叉樹1* @param r2 二叉樹2* @return 是否相同*/ public static boolean isSameRec(TreeNode r1, TreeNode r2) {if (r1 == null && r2 == null) { // 都是空return true;} else if (r1 == null || r2 == null) { // 有一個為空,一個不為空return false;}if (r1.val != r2.val) { // 兩個不為空,但是值不相同return false;}return isSameRec(r1.left, r2.left) && isSameRec(r1.right, r2.right); // 遞歸遍歷左右子節點 }

非遞歸解法:利用Stack對兩棵樹對應位置上的節點進行判斷是否相同。

/*** 5. 判斷兩棵二叉樹是否相同的樹(迭代)* 非遞歸* @param r1 二叉樹1* @param r2 二叉樹2* @return 是否相同*/ public static boolean isSame(TreeNode r1, TreeNode r2){if (r1 == null && r2 == null) { // 都是空return true;} else if (r1 == null || r2 == null) { // 有一個為空,一個不為空return false;}Stack<TreeNode> stack1 = new Stack<>();Stack<TreeNode> stack2 = new Stack<>();stack1.add(r1);stack2.add(r2);while (!stack1.isEmpty() && !stack2.isEmpty()) {TreeNode temp1 = stack1.pop();TreeNode temp2 = stack2.pop();if (temp1 == null && temp2 == null) { // 兩個元素都為空,因為添加的時候沒有對空節點做判斷continue;} else if (temp1 != null && temp2 != null && temp1.val == temp2.val) {stack1.push(temp1.left); // 相等則添加左右子節點判斷stack1.push(temp1.right);stack2.push(temp2.left);stack2.push(temp2.right);} else {return false;}}return true; }
6. 判斷二叉樹是不是平衡二叉樹

遞歸實現:借助前面實現好的求二叉樹高度的函數

  • 如果二叉樹為空, 返回真
  • 如果二叉樹不為空,如果左子樹和右子樹都是AVL樹并且左子樹和右子樹高度相差不大于1,返回真,其他返回假
/*** 6. 判斷二叉樹是不是平衡二叉樹* 遞歸* @param root 根節點* @return 是否二叉平衡樹(AVL樹)*/ public static boolean isAVLTree(TreeNode root) {if (root == null) {return true;}if (Math.abs(getDepth(root.left) - getDepth(root.right)) > 1) { // 左右子樹高度差大于1return false;}return isAVLTree(root.left) && isAVLTree(root.right); // 遞歸判斷左右子樹 }
7. 求二叉樹的鏡像

遞歸實現:破壞原來的樹,把原來的樹改成其鏡像

  • 如果二叉樹為空,返回空
  • 如果二叉樹不為空,求左子樹和右子樹的鏡像,然后交換左右子樹
/*** 7. 求二叉樹的鏡像* 遞歸* @param root 根節點* @return 鏡像二叉樹的根節點*/ public static TreeNode mirrorRec(TreeNode root) {if (root == null) {return root;}TreeNode left = mirrorRec(root.right); // 遞歸鏡像左右子樹TreeNode right = mirrorRec(root.left);root.left = left; // 更新根節點的左右子樹為鏡像后的樹root.right = right;return root; }

遞歸實現:不能破壞原來的樹,返回一個新的鏡像樹

  • 如果二叉樹為空,返回空
  • 如果二叉樹不為空,求左子樹和右子樹的鏡像,然后交換左右子樹
/*** 7. 求二叉樹的鏡像* 遞歸* @param root 根節點* @return 鏡像二叉樹的根節點*/ public static TreeNode mirrorCopyRec(TreeNode root) {if (root == null) {return root;}TreeNode newRoot = new TreeNode(root.val); // 創建新節點,然后交換左右子樹newRoot.left = mirrorCopyRec(root.right);newRoot.right = mirrorCopyRec(root.left);return newRoot; }

非遞歸實現:破壞原來的樹,把原來的樹改成其鏡像

/*** 7. 求二叉樹的鏡像* 非遞歸* @param root 根節點* @return 鏡像二叉樹的根節點*/ public static void mirror(TreeNode root) {if (root == null) {return ;}Stack<TreeNode> stack = new Stack<>();stack.push(root);while (!stack.isEmpty()){TreeNode cur = stack.pop();// 交換左右孩子TreeNode tmp = cur.right;cur.right = cur.left;cur.left = tmp;if(cur.right != null) {stack.push(cur.right);}if (cur.left != null) {stack.push(cur.left);}} }

非遞歸實現:不能破壞原來的樹,返回一個新的鏡像樹

/*** 7. 求二叉樹的鏡像* 非遞歸* @param root 根節點* @return 鏡像二叉樹的根節點*/ public static TreeNode mirrorCopy(TreeNode root) {if (root == null) {return null;}Stack<TreeNode> stack = new Stack<TreeNode>();Stack<TreeNode> newStack = new Stack<TreeNode>();stack.push(root);TreeNode newRoot = new TreeNode(root.val);newStack.push(newRoot);while (!stack.isEmpty()) {TreeNode cur = stack.pop();TreeNode newCur = newStack.pop();if (cur.right != null) {stack.push(cur.right);newCur.left = new TreeNode(cur.right.val);newStack.push(newCur.left);}if (cur.left != null) {stack.push(cur.left);newCur.right = new TreeNode(cur.left.val);newStack.push(newCur.right);}}return newRoot; }
8. 判斷兩個二叉樹是否互相鏡像

遞歸解法:與比較兩棵二叉樹是否相同解法一致(題5),非遞歸解法省略。

  • 比較r1的左子樹的鏡像是不是r2的右子樹
  • 比較r1的右子樹的鏡像是不是r2的左子樹
/*** 8. 判斷兩個樹是否互相鏡像* @param r1 二叉樹 1* @param r2 二叉樹 2* @return 是否互相鏡像*/ public static boolean isMirrorRec(TreeNode r1, TreeNode r2) {if (r1 == null && r2 == null) {return true;} else if (r1 == null || r2 == null) {return false;}if (r1.val != r2.val) {return false;}// 遞歸比較r1的左子樹的鏡像是不是r2右子樹// 和r1的右子樹的鏡像是不是r2的左子樹return isMirrorRec(r1.left, r2.right) && isMirrorRec(r1.right, r2.left); }
9. 求二叉樹中兩個節點的最低公共祖先節點

遞歸解法

  • 如果兩個節點分別在根節點的左子樹和右子樹,則返回根節點
  • 如果兩個節點都在左子樹,則遞歸處理左子樹;如果兩個節點都在右子樹,則遞歸處理右子樹
/*** 9. 求二叉樹中兩個節點的最低公共祖先節點* 遞歸* @param root 樹根節點* @param n1 第一個節點* @param n2 第二個節點* @return 最低公共祖先節點*/ public static TreeNode getLastCommonParentRec(TreeNode root, TreeNode n1, TreeNode n2) {if (findNodeRec(root.left, n1)) { // 如果n1在左子樹if (findNodeRec(root.right, n2)) { // 如果n2在右子樹return root; // 返回根節點} else { // 如果n2也在左子樹return getLastCommonParentRec(root.left, n1, n2); // 遞歸處理}} else { // 如果n1在右子樹if (findNodeRec(root.left, n2)) { // 如果n2在左子樹return root; // 返回根節點} else { // 如果n2在右子樹return getLastCommonParentRec(root.right, n1, n2); // 遞歸處理}} }/*** 遞歸判斷一個點是否在樹里* @param root 根節點* @param node 查找的節點* @return 是否找到該節點*/ private static boolean findNodeRec(TreeNode root, TreeNode node) {if (node == null || root == null) {return false;}if (root == node) {return true;}// 先嘗試在左子樹中查找boolean found = findNodeRec(root.left, node);if (!found) { // 如果查找不到,再在右子樹中查找found = findNodeRec(root.right, node);}return found; }/*** 9. 樹中兩個節點的最低公共祖先節點* 遞歸解法2(更簡單)* @param root 樹根節點* @param n1 第一個節點* @param n2 第二個節點* @return 最低公共祖先節點*/ public static TreeNode getLastCommonParentRec2(TreeNode root, TreeNode n1, TreeNode n2) {if (root == null) {return null;}// 如果有一個match,則說明當前node就是要找的最低公共祖先if (root.equals(n1) || root.equals(n2)) {return root;}TreeNode commonLeft = getLastCommonParentRec2(root.left, n1, n2);TreeNode commonRight = getLastCommonParentRec2(root.right, n1, n2);// 如果一個在左子樹找到,一個在右子樹找到,則說明root是唯一可能得最低公共祖先if (commonLeft != null && commonRight != null) {return root;}// 其他情況是要不然在左子樹要不然在右子樹if (commonLeft != null) {return commonLeft;}return commonRight; }

非遞歸算法:得到從二叉樹根節點到兩個節點的路徑,路徑從頭開始的最后一個公共節點就是它們的最低公共祖先節點

/*** 9. 樹中兩個節點的最低公共祖先節點* 非遞歸* @param root 樹根節點* @param n1 第一個節點* @param n2 第二個節點* @return 第一個公共祖先節點*/ public static TreeNode getLastCommonParent(TreeNode root, TreeNode n1, TreeNode n2) {if (root == null || n1 == null || n2 == null) {return null;}ArrayList<TreeNode> p1 = new ArrayList<>();boolean res1 = getNodePath(root, n1, p1);ArrayList<TreeNode> p2 = new ArrayList<>();boolean res2 = getNodePath(root, n2, p2);if (!res1 || !res2) {return null;}TreeNode last = null;Iterator<TreeNode> iter1 = p1.iterator();Iterator<TreeNode> iter2 = p2.iterator();while (iter1.hasNext() && iter2.hasNext()) {TreeNode tmp1 = iter1.next();TreeNode tmp2 = iter2.next();if (tmp1 == tmp2) {last = tmp1;} else { // 直到遇到非公共節點break;}}return last; }/*** 把從根節點到node路徑上所有的點都添加到path中* @param root 樹根節點* @param node 終點節點* @param path 路徑* @return 是否是目標節點*/ public static boolean getNodePath(TreeNode root, TreeNode node, ArrayList<TreeNode> path) {if (root == null) {return false;}path.add(root); // 把這個節點添加到路徑中if (root == node) {return true;}boolean found = false;found = getNodePath(root.left, node, path); // 先在左子樹中找if (!found) {found = getNodePath(root.right, node, path);}if (!found) { // 如果實在沒找到證明這個節點不在路徑中,刪除剛剛那個節點path.remove(root);}return found; }
10. 判斷是否為二分查找樹BST

遞歸解法:中序遍歷的結果應該是遞增的。

/*** 10. 判斷是否為二分查找樹BST* @param root 根節點* @param pre 上一個保存的節點* @return 是否為BST樹*/ public static boolean isValidBST(TreeNode root, int pre){if (root == null) {return true;}boolean left = isValidBST(root.left, pre);if (!left) {return false;}if(root.val <= pre) {return false;}pre = root.val;boolean right = isValidBST(root.right, pre);if(!right) {return false;}return true; }

非遞歸解法:參考非遞歸中序遍歷。

/** * 10. 判斷是否為二分查找樹BST* 非遞歸* @param root 根節點*/ public boolean isValidBST2(TreeNode root){Stack<TreeNode> stack = new Stack<>();//設置前驅節點TreeNode pre = null;while(root != null || !stack.isEmpty()){while (root != null) { // 將當前節點,以及左子樹一直入棧,循環結束時,root==nullstack.push(root);root = root.left;}root = stack.pop();//比較并更新前驅,與普通遍歷的區別就在下面四行if(pre != null && root.val <= pre.val){return false;}pre = root;root = root.right; //訪問右子樹}return true; }

總結

以上是生活随笔為你收集整理的数据结构 - 二叉树 - 面试中常见的二叉树算法题的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。