一、遞歸版本
思想:假設根結點為root,其中給定的兩個結點分別為A和B,它們分別都不為null。如果當前結點p為null,那么直接返回null,如果當前結點p是給定的結點中的其中一個結點,那么直接返回當前結點p(如果p是根結點,程序一次就返回了,下面的遞歸也不會出現)。如果當前節點不是A和B中的一個,那么需要分別去查找p的左右子樹,看看是否包含A或者B,查詢左右子樹后,如果查詢左子樹和查詢右子樹的結果都不為null,說明當前結點p就是最近的公共祖先。否則,如果查詢左子樹結果為null,那么返回查詢右子樹的結果。反之,返回查詢左子樹的結果。
public static TreeNode getParent(TreeNode root, TreeNode node1,TreeNode node2) { if(root == null || node1 == null || node2 == null) return null; //這里可以換成if(root == node1 || root == node2),我只是為了方便測試才這樣寫 if(root.val == node1.val || root.val == node2.val) return root; TreeNode left = getParent(root.left,node1,node2); TreeNode right = getParent(root.right,node1,node2); //如果左右子樹都能找到,那么當前節點就是最近的公共祖先節點 if(left != null && right != null) return root; //如果左子樹上沒有,那么返回右子樹的查找結果 if(left == null) return right; //否則返回左子樹的查找結果 else return left; }
二、非遞歸版本
思想:這里提供一種思路,代碼就不演示了。因為這個思想的實現代碼和查找從根到某個結點的路徑的思想一樣。首先,我們找出一條從根到A的路徑保存到棧或者數組,相同的方式找到一條從根到B的路徑也保存到棧或者數組(參考我的另一篇博客:查找從根到某結點的路徑)。然后開始遍歷這兩個數組,找到第一次下標相同但是值不同的那么數的下標,這個下標的前一個數就是最近公共祖先。我舉個例子:
假設A為結點3,B為結點4,那么從根到A的路徑為9---8---6---3,從根到B的路徑為9---7---4,遍歷這個兩個數組,發現9 == 9,而8 != 7,所以9就是最近公共祖先。