果然,這道題二刷還是不會做,回去看卡爾視頻了。結合靈神的題解,我對這道題有了一些新的理解。
首先這道題還是用遞歸來做,由于我們需要計算兩個節點的最近公共祖先,一定是從下往上來遍歷,只有先判斷左右子樹的情況以后,才能決定根節點是否為最近公共祖先,所以我們一定要采用后序遍歷,對于一個輸入節點,我們先對其左孩子和右孩子分別調用lowestCommonAncestor()
函數來判斷p
和q
是否在其中,分別用兩個指針left
和right
接收,如果left
和right
均不為空,說明p
和q
在當前節點的兩側,則當前節點就是最近公共祖先,如果left
和right
只有一個不為空,則說明p
和q
至少有一個節點在當前節點的一側,如果只有一個,則將當前的節點返回上去,在上層的某個根節點遲早會出現left
和right
均不為空的情況,再返回那個節點即可;如果兩個都在,則說明當前節點已經是最近公共祖先,將當前節點返回,在上層的節點中不可能出現left
和right
均不為空的情況,所以會一路返回到最外層的遞歸,得到最終結果。如果left
和right
均為空,則說明p
和q
不在當前子樹中,應當返回上層,去另外的子樹中尋找,直接返回空指針即可。
對于lowestCommonAncestor()
函數的返回值,我覺得靈神總結的很好,實際上就是最近公共祖先的候選值(不一定是),但是經過從下往上不斷更新,最終得到的候選節點一定是最近公共祖先。
/*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode(int x) : val(x), left(NULL), right(NULL) {}* };*/
class Solution {
public:TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {//遞歸終止條件if(!root) return nullptr;if(root == p || root == q) return root; //包含了q或q為最近公共祖先的情況//單層遞歸邏輯//在左子樹中搜索是否包含TreeNode* left = lowestCommonAncestor(root -> left, p, q);//在右子樹中搜索是否包含TreeNode* right = lowestCommonAncestor(root -> right, p, q);//中if(left && right) return root; //左右子樹各有一個,當前節點就是最近公共祖先if(!left && right) return right; //右孩子為候選節點,右子樹中至少包含p,q中的一個節點if(left && !right) return left; //左孩子為候選節點,右子樹中至少包含p,q中的一個節點else return nullptr; //當前節點的子樹中不包含p、q節點}
};