求樹中兩個節點的最低公共祖先節點(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)
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章