每日一题--找二叉树中两个结点的第一个祖先结点(Google推荐面试书--Cracking the Coding Interview)

题目

  • 原文:
    Design an algorithm and write code to find the first common ancestor of two nodes in a binary tree. Avoid storing additional nodes in a data structure. NOTE: This is not necessarily a binary search tree.
  • 译文:
    写程序在一棵二叉树中找到两个结点的第一个共同祖先。不允许存储额外的结点。注意: 这里不特指二叉查找树。

分析
这里提到不允许存储额外的结点,那么我们就不能通过先找到两个结点的所有父节点储存起来,再一一比对的方法,这里用哈希比map快。

TreeNode* first_ancestor(TreeNode* n1, TreeNode* n2){
if(n1 == NULL || n2== NULL) return NULL;
map<TreeNode*, bool> m;
while(n1){
m[n1] = true;
n1 = n1->parent;
}
while(n2 && !m[n2]){
n2 = n2->parent;
}
return n2;
}

取而代之的,如果不使用额外空间,并且没有父节点指针,我们从根节点开始依次向下找两节点共同祖先结点,直到找到最后一个这两结点的共同祖先结点。
这里值得注意的是:

关于指针的引用:
在主函数中定义了一个指针,要将这个指针做参数传给子函数,在子函数中开辟两兆内存,这个时候一定要用指针的引用。
因为指针所指的这块内存发生了改变,或者说指针的指向发生了改变。
主函数中只是定义了一个指针,并没有真正开辟内存,子函数中才真正开辟内存,指针指向哪才明确下来。
如果你有时候不清楚该不该用变量的引用做参数,那就记住一点: 用指针的引用总是没有问题的。因为传递变量的地址比传递变量本身总是改的快。
学习来源:https://blog.csdn.net/matrix_google/article/details/77543192

代码

#include<iostream>
using namespace std;

struct TreeNode {
	int val;
	TreeNode *leftchild, *rightchild;
};

TreeNode* createNode(int val) {
	TreeNode* node = new TreeNode;
	node->leftchild = NULL;
	node->rightchild = NULL;
	node->val = val;
	return node;
}

//void insert(TreeNode **tree, int val) {
//	if(*tree == NULL) {
//		*tree = createNode(val);
//		return;
//	}
//	else if((*tree)->val >= val) {
//		return insert(&(*tree)->leftchild, val);
//	}
//	else {
//		return insert(&(*tree)->rightchild, val);
//	} 
//}

void insert(TreeNode* &tree, int val) {
	if(tree == NULL) {
		tree = createNode(val);
		return;
	}
	else if(tree->val >= val) {
		return insert(tree->leftchild, val);
	}
	else {
		return insert(tree->rightchild, val);
	} 
}

TreeNode* findNode(TreeNode* head, int val) {
	if(head == NULL) {
		return NULL;
	}
	else if(head->val == val) {
		return head;
	}
	else if(head->val >= val) {
		return findNode(head->leftchild, val);
	} 
	else {
		return findNode(head->rightchild, val);
	}
}

bool father(TreeNode* n1, TreeNode* n2) {
	if(n1 == NULL) {
		return false;
	}
	else if(n1 == n2) {
		return true;
	}
	else {
		return father(n1->leftchild, n2) || father(n1->rightchild, n2);
	}	
}

void first_ancestor(TreeNode* head, TreeNode* n1, TreeNode* n2, TreeNode* &ancnode) {
	if(head == NULL || n1 == NULL || n2 == NULL) {
		return;
	}
	if(head && father(head, n1) && father(head, n2)) {
		ancnode = head;
		first_ancestor(head->leftchild, n1, n2, ancnode);
		first_ancestor(head->rightchild, n1, n2, ancnode);
	}
	return;
}

void printTree(TreeNode *tree) {
	if(tree != NULL) {
		cout << tree->val << " ";
		printTree(tree->leftchild);
		printTree(tree->rightchild);
	}
}

void deleteTree(TreeNode *tree) {
	if(tree != NULL) {
		deleteTree(tree->leftchild);
		deleteTree(tree->rightchild);
		delete tree;
	}
}

int main() {
	TreeNode *tree = NULL;
	int a[] = {
		5, 3, 8, 1, 4, 7, 10, 2, 6, 9, 11, 12
	};
	for(int i=0; i<12; ++i)
		insert(tree, a[i]);
		
	cout << "the tree is: ";
	printTree(tree);	
	cout << endl;
	
	TreeNode* n1 = findNode(tree, 1);
	TreeNode* n2 = findNode(tree, 2);
	
	TreeNode* ancnode = NULL;
	first_ancestor(tree, n1, n2, ancnode);
	cout << n1->val << " and " << n2->val << "'s father is" << ancnode->val << endl;
	
	deleteTree(tree);
}

结果展示
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_39860046/article/details/88070475