[英]Longest path between 2 Nodes
計算兩個節點之間的最長路徑。
路徑是拱形的。
簽名方法是:
public static int longestPath(Node n)
在下面的示例二叉樹中,它是4 (通過2-3-13-5-2)。
這就是我現在所擁有的,對於給定的樹,它只返回0。
public static int longestPath(Node n) {
if (n != null) {
longestPath(n, 0);
}
return 0;
}
private static int longestPath(Node n, int prevNodePath) {
if (n != null && n.getLeftSon() != null && n.getRightSon() != null) {
int currNodePath = countLeftNodes(n.getLeftSon()) + countRightNodes(n.getRightSon());
int leftLongestPath = countLeftNodes(n.getLeftSon().getLeftSon()) + countRightNodes(n.getLeftSon().getRightSon());
int rightLongestPath = countLeftNodes(n.getRightSon().getLeftSon()) + countRightNodes(n.getRightSon().getRightSon());
int longestPath = currNodePath > leftLongestPath ? currNodePath : leftLongestPath;
longestPath = longestPath > rightLongestPath ? longestPath : rightLongestPath;
longestPath(n.getLeftSon(), longestPath);
longestPath(n.getRightSon(), longestPath);
return longestPath > prevNodePath ? longestPath : prevNodePath;
}
return 0;
}
private static int countLeftNodes(Node n) {
if (n != null) {
return 1+ countLeftNodes(n.getLeftSon());
}
return 0;
}
private static int countRightNodes(Node n) {
if (n != null) {
return 1+ countRightNodes(n.getRightSon());
}
return 0;
}
我明白我在某個地方錯過了一個關鍵概念......當我嘗試跟蹤執行流程時,我的大腦發瘋了......
我是這么說的,通過找到根中最長的路徑,它的左右節點,然后遞歸到它的左右節點,傳遞它們從前一個方法調用的最長路徑,最后(當?)返回最長的路徑,我我不確定你是怎么回事的......
也許它就是這么簡單:
public static int longestPath(Node n) {
if (n != null) {
return longestPath(n, 0); // forgot return?
}
return 0;
}
它比一見鍾情更復雜。 考慮以下樹:
1
/ \
2 3
/ \
4 5
/ \ \
6 7 8
/ \ \
9 a b
在這種情況下,根節點甚至不在最長路徑中( a-7-4-2-5-8-b
)。
因此,您必須執行以下操作:對於每個節點n
您必須計算以下內容:
L
) R
) l
) r
) 然后,決定哪個組合最大化路徑長度:
L+R+2
,即從左子樹中的子路徑到當前節點,從當前節點到右子樹中的子路徑 l
,即只取左子樹並從路徑中排除當前節點(以及右子樹) r
,即只取右子樹並從路徑中排除當前節點(從而保留左子樹) 所以我會做一點點破解,並且每個節點都不返回一個int
,而是包含(L+R+2, l, r)
的三個整數。 然后,呼叫者必須根據上述規則決定如何處理此結果。
一個正確的算法是:
這個算法肯定會起作用,你也不僅限於二叉樹。 我不確定你的算法:
我是這么說的,通過找到根中的最長路徑,它的左右節點然后遞歸到它的左右節點,從它們傳遞前一個方法調用的最長路徑,最后(當???)返回最長的路徑,我不確定你是怎么回事的......
因為我不明白你究竟在描述什么。 你可以手工制作一個例子或嘗試更好地解釋它嗎? 這樣你可以更好地幫助理解它是否正確。
您似乎正在嘗試遞歸實現基本相同的事情,只是為二叉樹簡化。 但是,對於這個問題,您的代碼似乎相當復雜 請查看此處的討論,以獲得更簡單的實現。
這是我在C ++中的遞歸解決方案:
int longest_dis(Node* root) {
int height1, height2;
if( root==NULL)
return 0;
if( root->left == NULL ) && ( root->right == NULL )
return 0;
height1 = height(root->left); // height(Node* node) returns the height of a tree rooted at node
height2 = height(root->right);
if( root->left != NULL ) && ( root->right == NULL )
return max(height1+1, longest_dis(root->left) );
if( root->left == NULL ) && ( root->right != NULL )
return max(height2+1, longest_dis(root->right) );
return max(height1+height2+2, longest_dis(root->left), longestdis(root->right) );
}
public int longestPath() {
int[] result = longestPath(root);
return result[0] > result[1] ? result[0] : result[1];
}
// int[] {self-contained, root-to-leaf}
private int[] longestPath(BinaryTreeNode n) {
if (n == null) {
return new int[] { 0, 0 };
}
int[] left = longestPath(n.left);
int[] right = longestPath(n.right);
return new int[] { Util.max(left[0], right[0], left[1] + right[1] + 1),
Util.max(left[1], right[1]) + 1 };
}
簡單實施:
int maxDepth(Node root) {
if(root == null) {
return 0;
} else {
int ldepth = maxDepth(root.left);
int rdepth = maxDepth(root.right);
return ldepth>rdepth ? ldepth+1 : rdepth+1;
}
}
int longestPath(Node root)
{
if (root == null)
return 0;
int ldepth = maxDepth(root.left);
int rdepth = maxDepth(root.right);
int lLongPath = longestPath(root.left);
int rLongPath = longestPath(root.right);
return max(ldepth + rdepth + 1, max(lLongPath, rLongPath));
}
考慮到@phimuemue示例和@IVlad解決方案,我決定自己檢查一下,所以這是我在python中實現的@IVlad解決方案:
def longestPath(graph,start, path=[]):
nodes = {}
path=path+[start]
for node in graph[start]:
if node not in path:
deepestNode,maxdepth,maxpath = longestPath(graph,node,path)
nodes[node] = (deepestNode,maxdepth,maxpath)
maxdepth = -1
deepestNode = start
maxpath = []
for k,v in nodes.iteritems():
if v[1] > maxdepth:
deepestNode = v[0]
maxdepth = v[1]
maxpath = v[2]
return deepestNode,maxdepth +1,maxpath+[start]
if __name__ == '__main__':
graph = { '1' : ['2','3'],
'2' : ['1','4','5'],
'3' : ['1'],
'4' : ['2','6','7'],
'5' : ['2','8'],
'6' : ['4'],
'7' : ['4','9','a'],
'8' : ['5','b'],
'9' : ['7'],
'a' : ['7'],
'b' : ['8']
}
"""
1
/ \
2 3
/ \
4 5
/ \ \
6 7 8
/ \ \
9 a b
"""
deepestNode,maxdepth,maxpath = longestPath(graph,'1')
print longestPath(graph, deepestNode)
>>> ('9', 6, ['9', '7', '4', '2', '5', '8', 'b'])
我覺得你太復雜了。
考慮通過節點n的最長路徑並且不會到達n的父節點。 該路徑的長度與連接到n的兩個子區的高度之間的關系是什么?
搞清楚之后,檢查樹遞歸推理如下:
具有根n的子樹的最長路徑是以下三個中最長的路徑:
如果,對於每個節點n
,您的目標是計算這兩個數字:
n
):以n
為根的樹中最長路徑的長度 n
):以n
為根的樹的高度。 對於每個終端節點(具有null
左和右節點的節點),顯然f和h都是0。
現在,每個節點n
的h是:
n.left
和n.right
都為null
, n.right
0 n.left
為非null
n.left
1 + h( n.left
) n.right
為非null
n.right
1 + h( n.right
) n.left
),h( n.right
))如果n.left
和n.right
都是非null
f( n
)是:
n.left
和n.right
都為null
, n.right
0 n.left
),h( n
))如果只有n.left
是非null
n.right
是非null
n.left
和n.right
都是非null
(你需要弄清楚是什么取代了兩個“??”占位符。有一些選擇使這個策略有效。我已親自測試過。)
然后, longestPath(Node n)
只是f( n
):
public class SO3124566
{
static class Node
{
Node left, right;
public Node()
{
this(null, null);
}
public Node(Node left, Node right)
{
this.left = left;
this.right = right;
}
}
static int h(Node n)
{
// ...
}
static int f(Node n)
{
// ...
}
public static int longestPath(Node n)
{
return f(n);
}
public static void main(String[] args)
{
{ // @phimuemue's example
Node n6 = new Node(),
n9 = new Node(),
a = new Node(),
n7 = new Node(n9, a),
n4 = new Node(n6, n7),
b = new Node(),
n8 = new Node(null, b),
n5 = new Node(null, n8),
n2 = new Node(n4, n5),
n3 = new Node(),
n1 = new Node(n2, n3);
assert(longestPath(n1) == 6);
}{ // @Daniel Trebbien's example: http://pastebin.org/360444
Node k = new Node(),
j = new Node(k, null),
g = new Node(),
h = new Node(),
f = new Node(g, h),
e = new Node(f, null),
d = new Node(e, null),
c = new Node(d, null),
i = new Node(),
b = new Node(c, i),
a = new Node(j, b);
assert(longestPath(a) == 8);
}
assert(false); // just to make sure that assertions are enabled.
// An `AssertionError` is expected on the previous line only.
}
}
你應該能夠編寫f和h的遞歸實現來使這段代碼工作; 但是,這種解決方案非常低效。 其目的只是為了理解計算。
為了提高效率,您可以使用memoization或將其轉換為使用堆棧的非遞歸計算。
好吧,嗯,如果我正確理解你的問題,這是我的解決方案[但在C ++中(對不起)]:
int h(const Node<T> *root)
{
if (!root)
return 0;
else
return max(1+h(root->left), 1+h(root->right));
}
void longestPath(const Node<T> *root, int &max)
{
if (!root)
return;
int current = h(root->left) + h(root->right) + 1;
if (current > max) {
max = current;
}
longestPath(root->left, max);
longestPath(root->right, max);
}
int longest()
{
int max = 0;
longestPath(root, max);
return max;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.