劍指offer之求二叉樹中兩個(gè)節(jié)點(diǎn)的最低共同父節(jié)點(diǎn)
1 問題
求二叉樹中倆個(gè)節(jié)點(diǎn)的最低共同父節(jié)點(diǎn),比如二叉樹如下
4
2 6
1 3 5 7
比如節(jié)點(diǎn)1和3兩個(gè)節(jié)點(diǎn)的最低共同父節(jié)點(diǎn)是2,節(jié)點(diǎn)3和5兩個(gè)節(jié)點(diǎn)的最低共同父節(jié)點(diǎn)是4,節(jié)點(diǎn)5和6兩個(gè)節(jié)點(diǎn)的最低共同父節(jié)點(diǎn)是6,
也有可能其中1個(gè)節(jié)點(diǎn)或者2個(gè)節(jié)點(diǎn)不在二叉樹里面,那么他們就沒有最低共同父節(jié)點(diǎn)。
2 分析
4
2 6
1 3 5 7
比如我們求節(jié)點(diǎn)1和3兩個(gè)節(jié)點(diǎn)的最低共同父節(jié)點(diǎn),我們保存每個(gè)根節(jié)點(diǎn)到該節(jié)點(diǎn)的最短路徑節(jié)點(diǎn)值,比如節(jié)點(diǎn)1的路徑就是4->2->1 然后節(jié)點(diǎn)3的路徑是4->2->3,然后我們再把這個(gè)保存的2個(gè)路徑依次從尾巴進(jìn)行進(jìn)行比較,然后就能獲取兩個(gè)節(jié)點(diǎn)的最低共同父節(jié)點(diǎn)值。
3 代碼實(shí)現(xiàn)
#include <iostream>
#include <vector>
#include <stdlib.h>
using namespace std;
typedef struct Tree
{
int value;
struct Tree* left;
struct Tree* right;
Tree(int value) : value(value), left(NULL), right(NULL) {}
} Tree;
class CommonParentNode
{
public:
bool hasPath(Tree* head, Tree* node, std::vector<Tree *>& vector)
{
if (head == NULL)
return false;
///先把我們的遍歷節(jié)點(diǎn)保存到vector里面去
vector.push_back(head);
if (head == node)
return true;
//如果這樣寫只能說明子遞歸return值了,但是這個(gè)函數(shù)沒有返回值。
if (head->left != NULL && hasPath(head->left, node, vector))
return true;
if (head->right != NULL && hasPath(head->right, node, vector))
return true;
//這里一定要調(diào)用pop_back函數(shù),如果這個(gè)節(jié)點(diǎn)的左右子節(jié)點(diǎn)都為空或者左子樹或者右子樹里面不包含這個(gè)我們的節(jié)點(diǎn),
//這個(gè)節(jié)點(diǎn)就要彈出來,如果沒有這個(gè)函數(shù),那么我們的vector里面保存的先序遍歷到這個(gè)節(jié)點(diǎn)的所有節(jié)點(diǎn)值,
//而不是根節(jié)點(diǎn)到這個(gè)節(jié)點(diǎn)的最短距離。
vector.pop_back();
return false;
}
Tree* getCommmonParent(Tree* node, Tree* node1, Tree* node2)
{
if (node == NULL || node1 == NULL || node2 == NULL)
{
std::cout << "node == NULL || node1 == NULL || node2 == NULL" << std::endl;
return NULL;
}
vector<Tree *> vector1;
vector<Tree *> vector2;
bool result1 = hasPath(node, node1, vector1);
if (!result1)
return NULL;
bool result2 = hasPath(node, node2, vector2);
if (!result2)
return NULL;
//我們vector依次保存的是從頭結(jié)點(diǎn)到該節(jié)點(diǎn)的路徑,我們遍歷的時(shí)候應(yīng)該從vector的尾巴開始遍歷,注釋的遍歷錯(cuò)了,要注意
// for (int i = 0; i < vector1.size(); ++i)
// {
// for (int j = 0; j < vector2.size(); ++j)
// {
// //if (vector1[i]->value == vector2[j]->value)
// if (vector1[i] == vector2[j])
// {
// std::cout << "common parent node value is" << vector1[i]->value << std::endl;
// return vector1[i];
// }
// }
// }
for (int i = vector1.size() - 1; i >= 0; --i)
{
for (int j = vector2.size() - 1; j >= 0; --j)
{
//if (vector1[i]->value == vector2[j]->value)
if (vector1[i] == vector2[j])
{
return vector1[i];
}
}
}
return NULL;
}
};
int main() {
Tree *node1 , *node2 , *node3, *node4, *node5, *node6, *node7, *node8;
node1 = (Tree *)malloc(sizeof(Tree));
node2 = (Tree *)malloc(sizeof(Tree));
node3 = (Tree *)malloc(sizeof(Tree));
node4 = (Tree *)malloc(sizeof(Tree));
node5 = (Tree *)malloc(sizeof(Tree));
node6 = (Tree *)malloc(sizeof(Tree));
node7 = (Tree *)malloc(sizeof(Tree));
node8 = (Tree *)malloc(sizeof(Tree));
node1->value = 4;
node2->value = 2;
node3->value = 6;
node4->value = 1;
node5->value = 3;
node6->value = 5;
node7->value = 7;
node8->value = 8;
node1->left = node2;
node1->right = node3;
node2->left = node4;
node2->right = node5;
node3->left = node6;
node3->right = node7;
node4->left = NULL;
node4->right = NULL;
node5->left = NULL;
node5->right = NULL;
node6->left = NULL;
node6->right = NULL;
node7->left = NULL;
node7->right = NULL;
/***
4
2 6
1 3 5 7
**/
CommonParentNode commonParentNode;
Tree *commonTreeNode = NULL;
commonTreeNode = commonParentNode.getCommmonParent(node1, node5, node7);
if (!commonTreeNode)
{
std::cout << "the two node do not find commonTreeNode" << std::endl;
return -1;
}
std::cout << "commonTreeNode parent node value is " << commonTreeNode->value << std::endl;
return 0;
}
4 運(yùn)行結(jié)果
commonTreeNode parent node value is 4
5 總結(jié)
這個(gè)題目的思路是保存根節(jié)點(diǎn)到每個(gè)節(jié)點(diǎn)中途最短路徑父節(jié)點(diǎn)值,然后進(jìn)行比較,同時(shí)我們應(yīng)該可以知道求根節(jié)點(diǎn)到該節(jié)點(diǎn)最短路徑的每個(gè)節(jié)點(diǎn)值,就是vector里面保存的每個(gè)節(jié)點(diǎn),同時(shí)也知道根節(jié)點(diǎn)到該節(jié)點(diǎn)的高度值,也就是這個(gè)vecter里面保存數(shù)據(jù)的大小,既vector.size()函數(shù)的值,代碼和上面部分代碼一樣。
bool hasPath(Tree* head, Tree* node, std::vector<Tree *>& vector)
{
if (head == NULL)
return false;
///先把我們的遍歷節(jié)點(diǎn)保存到vector里面去
vector.push_back(head);
if (head == node)
return true;
//如果這樣寫只能說明子遞歸return值了,但是這個(gè)函數(shù)沒有返回值。
if (head->left != NULL && hasPath(head->left, node, vector))
return true;
if (head->right != NULL && hasPath(head->right, node, vector))
return true;
//這里一定要調(diào)用pop_back函數(shù),如果這個(gè)節(jié)點(diǎn)的左右子節(jié)點(diǎn)都為空或者左子樹或者右子樹里面不包含這個(gè)我們的節(jié)點(diǎn),
//這個(gè)節(jié)點(diǎn)就要彈出來,如果沒有這個(gè)函數(shù),那么我們的vector里面保存的先序遍歷到這個(gè)節(jié)點(diǎn)的所有節(jié)點(diǎn)值,
//而不是根節(jié)點(diǎn)到這個(gè)節(jié)點(diǎn)的最短距離。
vector.pop_back();
return false;
}
很經(jīng)典的代碼。
作者:chen.yu
深信服三年半工作經(jīng)驗(yàn),目前就職游戲廠商,希望能和大家交流和學(xué)習(xí),
微信公眾號(hào):編程入門到禿頭 或掃描下面二維碼
零基礎(chǔ)入門進(jìn)階人工智能(鏈接)