何時使用後序遍歷呢?
若是當前節點要作的事情須要經過左右子樹的計算結果推導出來,就要用到後序遍歷
二叉樹相關題目最核心的的思路就是明確當前節點須要作的事情是什麼???
1.我確定得知道左右子樹是否是合法的BST,若是這倆兒子有一個不是BST,以我爲根的這棵樹確定不是BST。
2.若是左右子樹都是合法的BST,我得瞅瞅左右子樹加上本身仍是不是合法的BST,由於按照BST的定義,當前節點的值應該大於左子樹的最大值,小於右子樹的最小值,不然就破壞了BST的性質。
3.由於題目要計算最大的節點之和,若是左右子樹加上我本身仍是一棵合法的BST,也就是說以我爲根的整棵樹是一棵BST,那我須要知道咱們這棵的全部節點之和是多少。
站在當前節點的視角,須要知道如下具體信息:
1.左右子樹是不是BST。
2.左子樹的最大值和右子樹的最小值。
3.左右子樹的節點值之和。
嘗試用僞碼寫出算法的大體邏輯:算法
//全局變量,記錄BST最大節點值和 int maxSum=0; //遍歷二叉樹 void traverse(TreeNode root){ //base case if(root==null){ return; } //前序遍歷代碼 //判斷左右子樹是否是BST if(!isBST(root.left)||!isBST(root.right)){ goto next; } //計算左子樹的最大值和右子樹的最小值 int leftMax=findMax(root.left); int rightMin=findMin(root.right); //判斷以root節點爲根的樹是否是BST if(root.val<=leftMax||root.val>=rightMin){ goto next; } //若是條件都符合,計算當前BST的節點之和 int leftSum=findSum(root.left); int rightSum=findSum(root.right); int rootSum=leftSum+rightSum+root.val; //計算BST節點的最大和 this.maxSum=Math.max(maxSum,rootSum); //遞歸左右子樹 next: traverse(root.left); traverse(root.right); } //計算以root爲根的二叉樹的最大值 int findMax(TreeNode root){} //計算以root爲根的二叉樹的最小值 int findMin(TreeNode root){}; //計算以root爲根的二叉樹的節點和 int findSum(TreeNode root){}; //判斷以root爲根的二叉樹是不是BST boolean isBST(TreeNode root){}
其中四個輔助函數比較簡單,其中只有判斷合法BST的函數稍有技術含量,前文二叉搜索樹操做集錦
稍做分析就會發現,這幾個輔助函數都是遞歸函數,都要遍歷輸入的二叉樹,外加traverse函數自己的遞歸,能夠說是遞歸上加遞歸,因此複雜度很高
只要把前序遍歷變成後序遍歷,讓traverse函數把輔助函數作的事順便作掉數組
int maxSum=0; int [] traverse(TreeNode root){ int[] left=traverse(root.left); int[] right=traverse(root.right); }
traverse(root)返回一個大小爲4的int數組,咱們暫且稱他爲res,其中:
res[0]-記錄以root爲根的二叉樹是不是BST,若爲1則說明是BST,若爲0則說明不是BST。
res[1]-記錄以root爲根的二叉樹的全部節點中的最小值
res[2]-記錄以root爲根二叉樹全部節點中的最大值
res[3]-記錄以root爲根的二叉樹全部節點值之和
咱們要視圖經過left和right正確地導出res數組函數
int[] traverse(TreeNode root){ if(root==null){ return new int[]{ 1,Integer>MAX_VALUE,Integer>MIN_VALUE,0 }; } //遞歸計算左右子樹 int [] left=traverse(root.left); int [] right=traverse(root.right); int[] res=new int[4]; //這個if在判斷以root爲根的二叉樹是否是BST if(left[0]==1&&right[0]==1&&root.val>left[2]&&root.val<right[1]){ //以root爲根的是二叉樹是BST res[0]=1; res[1]=Math.min(left[1],root.val); res[2]=Math.max(right[2],root.val); res[3]=left[3]+right[3]+root.val; maxSum=Math.max(maxSum,res[3]); }else{ res[0]=0; } return res; }
這後序遍歷也不是亂用的,這裏爲何能用呢???
以root爲根的二叉樹的節點之和,是否是能夠經過左右子樹的和加上root.val計算出來?
以root爲根的二叉樹的最小值/最大值,是否是能夠經過左右子樹的最小值/最大值和root.val比較出來?
判斷以root爲根的二叉樹是否是BST,是否是得先判斷左右子樹是否是BST?是否是還得看看左右子樹左右子樹的最大值和最小值?
若是當前節點要作的事情須要經過經過左右子樹的計算結果推導出來,就要用到後序this