求树中两个节点的最低公共祖先节点(go)

该题目有以下几种情况可以考虑

1. 树是二叉搜索树,二叉搜索树的特点是根节点值大于所有左子树节点值,小于所有右子树节点值,则最低公共祖先即该节点值大于给定两个节点中的一个值,小于另外一个节点的值,go代码实现如下

type TreeNode struct {
	Val int
	Left *TreeNode
	Right *TreeNode
}

// 如果树是二叉搜索树
func getLastCommentNode(node1, node2, root *TreeNode) *TreeNode {
	if nil == root || nil == node1 || nil == node2 {
		return nil
	}
	if node1.Val < root.Val && node2.Val < root.Val {
		return getLastCommentNode(node1, node2, root.Left)
	}
	if node1.Val > root.Val && node2.Val > root.Val {
		return getLastCommentNode(node1, node2, root.Right)
	}
	return root
}

2. 树是普通二叉树,但节点有指向父节点的指针,则该问题转化为了求两个链表第一个相交的节点, go代码实现如下

type TreeNode1 struct {
	Val int
	Child []*TreeNode1
	Parent *TreeNode1
}

// 带有父指针的普通树
func getLastCommentNode(node1, node2 *TreeNode1) *TreeNode1 {
	len1 := getLengthToRoot(node1)
	len2 := getLengthToRoot(node2)
	if len1 > len2 {
		for i := 0; i < len1 - len2; i++ {
			node1 = node1.Parent
		}
	} else if len1 < len2 {
		for i := 0; i < len2 - len1; i++ {
			node2 = node2.Parent
		}
	}
	for node1 != nil && node2 != nil {
		if node1.Parent == node2.Parent {
			return node1.Parent
		}
		node1 = node1.Parent
		node2 = node2.Parent
	}
	return nil
}

func getLengthToRoot(node *TreeNode1) int {
	if node == nil {
		return 0
	}
	return 1 + getLengthToRoot(node.Parent)
}

3. 如果该树为普通树,且没有指向父节点的指针,则该问题可以转化成一下方式求解:a. 如果给定的两个节点都在当前节点同一个孩子的节点下面,则当前节点变成当前节点的孩子节点;b. 如果给定的两个节点在当前节点不同的孩子节点下面,则当前节点就是最低公共祖先,代码实现分为递归和非递归

递归实现(go):

type TreeNode2 struct {
	Val int
	Child []*TreeNode2
}
// 普通树 递归实现
func getLastComentNode(node1, node2, root *TreeNode2) *TreeNode2 {
	if root == nil {
		return nil
	}
	found1, local1 := findNodeAndLocal(node1, root)
	found2, local2 := findNodeAndLocal(node2, root)
	if !found2 || !found1 {
		return nil
	}
	if local2 == local1 {
		return getLastComentNode(node1, node2, root.Child[local1])
	}
	return root
}

func findNode(node, root *TreeNode2) (bool) {
	if root == nil {
		return false
	}
	if root == node {
		return true
	}
	found := false
	for i := 0; i < len(root.Child) && !found; i++ {
		found = findNode(node, root.Child[i])
	}
	return found
}

func findNodeAndLocal(node, root *TreeNode2) (bool, int) {
	if root == nil {
		return false, -1
	}
	found := false
	local := -1
	for i := 0; i < len(root.Child) && !found; i++ {
		found = findNode(node, root.Child[i])
		if found {
			local = i
		}
	}
	return found, local
}

非递归实现(go):

//普通树 非递归实现
func getLastComentNode(node1, node2, root *TreeNode2) *TreeNode2 {
	path1 := list.New()
	path2 := list.New()
	if nil == root || nil == node1 || nil == node2 {
		return nil
	}
	getPath(node1, root, path1)
	getPath(node2, root, path2)
	var lastParentNode *TreeNode2
	for path1.Front() != nil && path2.Front() != nil {
		if path1.Front().Value == path2.Front().Value {
			lastParentNode = path1.Front().Value.(*TreeNode2)
		}
		path1.Remove(path1.Front())
		path2.Remove(path2.Front())
	}
	return lastParentNode
}

func getPath(node, root *TreeNode2, path *list.List) bool {
	if node == root {
		return true
	}
	path.PushBack(root)
	found := false
	for i:= 0; i < len(root.Child) && !found; i++ {
		found = getPath(node, root.Child[i], path)
	}
	if !found {
		path.Remove(path.Back())
	}
	return found
}

var c = &TreeNode2{Val: 3}
var d = &TreeNode2{Val: 4}
var e = &TreeNode2{Val: 5}
var b = &TreeNode2{Val: 2, Child: []*TreeNode2{d, e}}
var a = &TreeNode2{Val: 1, Child: []*TreeNode2{b, c}}

func TestTree(t *testing.T) {
	temp := getLastComentNode(b, e, a)
	fmt.Println(temp)
}

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是利用栈实现任意两个树中节点的最近公共祖先的C语言代码: ```c #include<stdio.h> #include<stdlib.h> #define MAXSIZE 100 // 栈的最大容量 typedef struct TreeNode { int val; struct TreeNode *left; struct TreeNode *right; } TreeNode; typedef struct Stack { TreeNode *data[MAXSIZE]; int top; } Stack; // 创建一个栈 Stack *createStack() { Stack *s = (Stack*)malloc(sizeof(Stack)); s->top = -1; return s; } // 判断栈是否为空 int isEmpty(Stack *s) { return s->top == -1; } // 判断栈是否已满 int isFull(Stack *s) { return s->top == MAXSIZE - 1; } // 入栈 void push(Stack *s, TreeNode *node) { if (isFull(s)) { return; } s->top++; s->data[s->top] = node; } // 出栈 TreeNode *pop(Stack *s) { if (isEmpty(s)) { return NULL; } TreeNode *node = s->data[s->top]; s->top--; return node; } // 求两个节点的最近公共祖先 TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) { Stack *s1 = createStack(); Stack *s2 = createStack(); TreeNode *node = root, *last = NULL; while (node || !isEmpty(s1)) { if (node) { push(s1, node); if (node == p) { while (!isEmpty(s2)) { pop(s2); } for (int i = 0; i <= s1->top; i++) { push(s2, s1->data[i]); } } if (node == q) { while (!isEmpty(s1)) { pop(s1); } for (int i = 0; i <= s2->top; i++) { push(s1, s2->data[i]); } } node = node->left; } else { TreeNode *top = s1->data[s1->top]; if (top->right && top->right != last) { node = top->right; } else { last = pop(s1); } } } return s1->data[s1->top]; } int main() { TreeNode *root = (TreeNode*)malloc(sizeof(TreeNode)); root->val = 3; root->left = (TreeNode*)malloc(sizeof(TreeNode)); root->left->val = 5; root->left->left = (TreeNode*)malloc(sizeof(TreeNode)); root->left->left->val = 6; root->left->right = (TreeNode*)malloc(sizeof(TreeNode)); root->left->right->val = 2; root->left->right->left = (TreeNode*)malloc(sizeof(TreeNode)); root->left->right->left->val = 7; root->left->right->right = (TreeNode*)malloc(sizeof(TreeNode)); root->left->right->right->val = 4; root->right = (TreeNode*)malloc(sizeof(TreeNode)); root->right->val = 1; root->right->left = (TreeNode*)malloc(sizeof(TreeNode)); root->right->left->val = 0; root->right->right = (TreeNode*)malloc(sizeof(TreeNode)); root->right->right->val = 8; TreeNode *p = root->left, *q = root->right; TreeNode *ancestor = lowestCommonAncestor(root, p, q); printf("The lowest common ancestor of node %d and node %d is node %d.\n", p->val, q->val, ancestor->val); return 0; } ``` 在此代码中,我们利用两个栈`s1`和`s2`分别存储从根节点两个目标节点的路径。具体实现方法是,从根节点开始遍历树,每当遍历到一个节点时,就将该节点入栈`s1`。如果遍历到了目标节点`p`,则将栈`s2`清空,并将栈`s1`中的所有节点依次出栈并入栈`s2`中。如果遍历到了目标节点`q`,则将栈`s1`清空,并将栈`s2`中的所有节点依次出栈并入栈`s1`中。最终,栈`s1`中的栈顶元素即为两个目标节点的最近公共祖先

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值