案例一:
面試題49把字符串轉換成整數
案例二:
面試題50樹中兩個節點的最低公共祖先
題目:
輸入兩個樹節點,求它們的最低公共祖先。
1.如果是二叉搜索樹,二叉搜索樹是排序過的,位於左子樹的節點都比父節點小,位於右子樹的節點都比父節點大。
我們只需要從樹的根節點開始和兩個輸入的節點進行比較。如果當前節點的值比兩個節點的值都大,最低公共祖先一定在當前節點的左子樹中,下一步遍歷當前節點的左子節點。如果當前節點的值比兩個節點的值都小,那麼最低公共父節點一定在當前節點的右子樹中,於是下一步遍歷當前節點的右子節點。
2.如果不是二叉搜索樹,但是樹的節點中有指向父節點的指針。這個問題可以轉換爲求兩個鏈表的第一個公共節點。
從樹的每一個葉子節點開始都有一個由指向父節點的指針串起來的鏈表,這些鏈表的尾指針都是樹的根節點。
輸入兩個節點,那麼這兩個節點位於兩個鏈表上,他們的最低公共祖先剛好就是這兩個鏈表的第一個公共節點。
比如輸入F和H,F在鏈表F-D-B-A上,而H在鏈表H-E-B-A上,這兩個鏈表的第一個交點B剛好也是它們的最低公共祖先。
3.不是二叉搜索樹,樹的節點中也沒有指向父節點的指針。
用兩個鏈表分別保存從根節點到輸入的兩個節點的路徑,然後把問題轉換成兩個鏈表的最後公共節點。
需要遍歷兩次樹得到兩個鏈表,每次時間複雜度O(n),
得到的兩條路徑的長度在最差情況下是O(n),通常情況下兩條路徑的長度是O(logn)。
整個程序的時間複雜度3O(n),空間複雜度是2O(n)。
/**
* 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:
bool getNodePath(TreeNode* pRoot, TreeNode* pNode, list<TreeNode*> &path){
if(pRoot==pNode){
path.push_back(pNode);//與劍指offer不同,用來解決p可能是q的祖先
return true;
}
path.push_back(pRoot);
bool found = false;
if(pRoot->left)found = getNodePath(pRoot->left, pNode, path);
if(!found&&pRoot->right){
found = getNodePath(pRoot->right, pNode, path);
}
if(!found)path.pop_back();
return found;
}
TreeNode* getLastCommonNode(const list<TreeNode*> &path1, const list<TreeNode*> &path2){
list<TreeNode*>::const_iterator p1 = path1.begin();
list<TreeNode*>::const_iterator p2 = path2.begin();
TreeNode* result = nullptr;
while(p1!=path1.end()&&p2!=path2.end()){
if(*p1==*p2) result = *p1;
++p1;
++p2;
}
return result;
}
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
if(root==nullptr||p==nullptr||q==nullptr)return nullptr;
list<TreeNode*> path1, path2;
getNodePath(root, p, path1);
getNodePath(root, q, path2);
return getLastCommonNode(path1, path2);
}
};