My code:
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
public class Solution {
private TreeNode ancestor = null;
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if (root == null)
return null;
else if (p == q)
return p;
boolean[] ret = findAncestor(root, p, q);
return ancestor;
}
private boolean[] findAncestor(TreeNode root, TreeNode p, TreeNode q) {
boolean[] retLeft = null;
boolean[] retRight = null;
boolean[] ret = new boolean[3];
if (root.left != null) {
retLeft = findAncestor(root.left, p, q);
if (retLeft != null) {
ret[0] |= retLeft[0];
ret[1] |= retLeft[1];
ret[2] |= retLeft[2];
if (ret[2])
return ret;
}
}
if (root.right != null) {
retRight = findAncestor(root.right, p, q);
if (retRight != null) {
ret[0] |= retRight[0];
ret[1] |= retRight[1];
ret[2] |= retRight[2];
if (ret[2])
return ret;
}
}
if (root == p)
ret[0] = true;
else if (root == q)
ret[1] = true;
if (ret[0] && ret[1]) {
ret[2] = true;
ancestor = root;
}
return ret;
}
}
My test result:
這道題目還是挺帶勁的。想了挺久。最后終于寫出來,感覺自己功力還是挺深厚的。
首先提醒。
**形參是無法改變實(shí)參的,即使傳入的是指針。除非是容器。比如這道題目中,
我一開始這么寫的函數(shù)。
private boolean[] findAncestor(TreeNode root, TreeNode p, TreeNode q, TreeNode ancestor) {....}
然后在主函數(shù)中傳入ancestor,妄想著在遞歸中,給他賦值,然后改變實(shí)參。也就是主函數(shù)中的ancestor。但是,是無法改變的。遞歸的時候,只是把這個指針的地址壓入棧中。如果這個指針取得了新的地址,那么在這段棧里面,他的值會被改變成另外一個地址值。但是這個子函數(shù)并沒有返回這個地址,那么,當(dāng)這個子函數(shù)結(jié)束時,這段地址就被拋棄了。就算他改變了,也不能使上一層的實(shí)參指針的地址值發(fā)生改變。
什么情況下會改變呢?當(dāng)實(shí)參是容器時,那么傳入的容器增減,是可以反映到實(shí)參的。
所以,permutation那類題,不能拷貝地址值給arraylist而必須新建一個arraylist拷貝所有元素,然后再添加進(jìn)大arraylist。同樣的,需要不斷地remove。
**
這道題目是什么思想呢。
我返回一個三個布爾量的數(shù)組。他們的意義是。
boolean[] ret
ret[0] p is find -> true
ret[1] q is find -> true
ret[2] pq is find -> ret[0] & ret[1] == true -> true
然后是用post-order 來遍歷的。
因?yàn)槲野l(fā)現(xiàn), pre-order都是先遍歷頭結(jié)點(diǎn),然后再左再右。
而 post-order 是先遍歷子節(jié)點(diǎn),左右,在往上。
所以,當(dāng)我到達(dá)root時,
我先pre order 左子樹,
然后看下這個返回的布爾數(shù)組,ret[2] 是否為真,如果為真,那么就是已經(jīng)找到了,我就不需要再找了,直接返回。
如果返回的布爾數(shù)組不是空的,但ret[2] false。
那么,我就將 ret[0], ret[1] 與這個布爾數(shù)組對應(yīng)為進(jìn)行或操作。只要pq有一個被找到,就可以通過或操作反映到ret上。
對右子樹進(jìn)行同樣的操作。
然后再判斷root自己。是否是pq
再判斷下ret[0], ret[1] 是否都為真,如果是的,就代表都找到了,且祖先就是root。
ret[2] 設(shè)置為true并返回。
否則就直接返回。
同時,我一開始的代碼不是這樣的。因?yàn)樽雍瘮?shù)可能返回null,為了避免bug,我就一開始給左右布爾數(shù)組都申請了內(nèi)存。但是想到今早看書,老教授的一句話。
在遞歸函數(shù)中申請內(nèi)存是一件十分消耗資源的事,能不做就盡量不做。所以我最后找了個辦法避免了。多寫了幾個if語句,所以運(yùn)行時間可能要慢一點(diǎn),但是一定省掉了許多內(nèi)存。
**
總結(jié): post-order tree
**
Anyway, Good luck, Richardo!
My code:
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
public class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if (root == null) {
return null;
}
else if (root == p || root == q) {
return root;
}
TreeNode left = lowestCommonAncestor(root.left, p, q);
TreeNode right = lowestCommonAncestor(root.right, p, q);
if (left == null && right == null) {
return null;
}
else if (left == null || right == null) {
return left == null ? right : left;
}
else {
return root;
}
}
}
同學(xué)提醒后做了出來。是一個dfs
bottom up
post-order
如果root == p or q,就返回p or q
否則,繼續(xù)dfs,再判斷返回的左右是否都是空,如果是,就代表p,q不在這個sub tree里面,就返回null
如果有一個為空,則另一個可能是找到的p or q,也可能就是他們的ancestor,直接往上層返回就行。
如果左右都不是空,那么當(dāng)前root就是ancestor,直接返回root.
思路就是這樣的了。
Anyway, Good luck, Richardo! -- 09/05/2016
My code:
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
public class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
HashMap<TreeNode, TreeNode> map = new HashMap<TreeNode, TreeNode>();
Stack<TreeNode> st = new Stack<TreeNode>();
map.put(root, null);
st.push(root);
while (!map.containsKey(p) || !map.containsKey(q)) {
TreeNode curr = st.pop();
if (curr.left != null) {
map.put(curr.left, curr);
st.push(curr.left);
}
if (curr.right != null) {
map.put(curr.right, curr);
st.push(curr.right);
}
}
HashSet<TreeNode> set = new HashSet<TreeNode>();
while (p != null) {
set.add(p);
p = map.get(p);
}
while (q != null) {
if (set.contains(q)) {
return q;
}
set.add(q);
q = map.get(q);
}
return null;
}
}
reference:
https://discuss.leetcode.com/topic/27479/java-python-iterative-solution/2
這才是真正優(yōu)美的解決方法。
利用一個map保持父子關(guān)系。如果 union find 一般。
然后,利用它,我們還可以找到 p and q 的路徑。
Tree + HashMap, 這是一種全新的組合,第一次接觸。
Anyway, Good luck, Richardo! -- 09/24/2016