[英]maximum length of a descending path in a tree which always goes left|right
我正在為技術面試做准備,所以基本上從一開始就學習算法:) 我們獲得了 BST。 我需要在其中找到一條 desc 路徑的最大長度,它總是向左或向右 換句話說,示例樹的降序路徑為 2,即 15-10-6
5
/ \
2 15
/
10
/ \
6 14
我對算法問題很陌生。我解決這個問題的步驟是什么?
我的想法是使用 DFS 和計數器來存儲最長路徑。 但我不知道如何使用遞歸來完成這項工作,而遞歸對於這種數據結構來說似乎更自然。
任何建議/方向?
措辭有點混亂,但我認為你的意思是最大的
您分兩次完成此操作,一次查找最大左側路徑,另一次查找最大右側路徑(然后取兩者中的最大值)。 或者您可以一次完成,同時完成這兩項工作。
對於每個節點,您想知道三個值:
如果您以遞歸方式執行此操作,這意味着遞歸應返回這三個值,可能作為一個小數組或作為一個簡單的三字段對象。
這看起來像
Results calculate(Tree node) {
if (node == null) return new Results(0,0,0);
else {
Results leftResults = calculate(node.left);
Results rightResults = calculate(node.right);
int leftLength = 1 + leftResults.leftLength;
int rightLength = 1 + rightResults.rightLength;
int maxLength = Math.max(Math.max(leftLength, rightLength),
Math.max(leftResults.maxLength, rightResults.maxLength));
return new Results(leftLength, rightLength, maxLength);
}
}
並且整體結果將只是calculate(root).maxLength
。
實際上,這是我測試過的 Codibility 上的一個問題。 我只是為了討論它而提到一個非遞歸解決方案。
樹本身有一個可以修改的值。
我在這里找到了一個比遞歸解決方案更好的解決方案,但我沒有用 Java 編程,所以我將把 C# 解決方案放在正確的算法上:
public class Tree
{
public int x;
public Tree l;
public Tree r;
}
class solution
{
public int solution(Tree T)
{
// write your code in C# 5.0 with .NET 4.5 (Mono)
List<Tree> toProcess = new List<Tree>(10000);
if (T == null)
return 0;
int maxLength = 0;
T.x = 0;
toProcess.Add(T);
while (toProcess.Count != 0)
{
Tree currNode = toProcess[toProcess.Count-1];
toProcess.RemoveAt(toProcess.Count - 1);
int remainder = currNode.x % 100000;
if (currNode.l != null)
{
currNode.l.x = 1 + remainder;
maxLength = Math.Max(maxLength, currNode.l.x);
toProcess.Add(currNode.l);
}
if (currNode.r != null)
{
currNode.r.x = 100000 + (currNode.x - remainder);
maxLength = Math.Max(maxLength, currNode.r.x / 100000);
toProcess.Add(currNode.r);
}
}
return maxLength;
}
}
如果你計時,這比通過倍數回避要快。 這個想法是在每個節點上,您在子節點中存儲更長的長度並將它們附加到列表(如果需要,您可以使用堆棧)以供稍后處理。 您使用 int 來存儲計數。 Codibility 上的原始問題提到不超過 10 000 個節點,最大深度為 800。
最后一個優化是將我使用的 100000 替換為二進制移位來分隔左右長度,這會更快,即使用前 16 位存儲左邊的長度,其余的存儲右邊的長度,但我沒有當我開始使用遞歸方法時,有足夠的時間來做到這一點。
編輯:我做了按位,太糟糕了我沒有時間確保它是正確的並提交它,因為它比遞歸快得多:
public int solution(Tree T)
{
// write your code in C# 5.0 with .NET 4.5 (Mono)
List<Tree> toProcess = new List<Tree>(10000);
int rightmask = 0x0000FFFF;
int leftmask = ~0x0000FFFF;
if (T == null)
return 0;
int maxLength = 0;
T.x = 0;
toProcess.Add(T);
while (toProcess.Count != 0)
{
Tree currNode = toProcess[toProcess.Count-1];
toProcess.RemoveAt(toProcess.Count - 1);
if (currNode.l != null)
{
int leftpart = (currNode.x & leftmask) >> 16;
int newLength = 1 + leftpart;
currNode.l.x = newLength << 16;
maxLength = Math.Max(maxLength, newLength);
toProcess.Add(currNode.l);
}
if (currNode.r != null)
{
int rightpart = (currNode.x & rightmask);
currNode.r.x = 1 + rightpart;
maxLength = Math.Max(maxLength, currNode.r.x);
toProcess.Add(currNode.r);
}
}
return maxLength;
}
從節點v
調用的遞歸函數應返回 3 個值:
1. Maximum descending path which goes always left or always right in subtree rooted in v
2. Maximum length of path which goes always left starting from v
3. Maximum length of path which goes always right starting from v
讓我們分別稱這些值(V1, V2, V3)
顯然,對於樹中的任何葉子,上述所有值都等於 0。
讓我們考慮任何內部節點v
。
設(L1, L2, L3)
是遞歸調用v
左子節點返回的值。
令(R1, R2, R3)
為遞歸調用v
右孩子所返回的值。
然后v
,為了計算(V1, V2, V3)
只需要組合從左孩子和右孩子返回的結果:
如果存在左孩子,則V2
等於L2 + 1
。 否則為 0。
如果存在右孩子,則V3
等於R3 + 1
。 否則為 0。
V1
等於max(L1, R1, V2, V3)
這是問題的工作代碼。 給出一個 11 節點的二叉樹用於測試:
公共類節點{
int L = 0;
int R = 0;
Node left = null;
Node right = null;
}
公共類 BTree {
void calculate_paths(Node root) {
if (root.left != null) {
calculate_paths(root.left);
root.L = root.left.L + 1;
}
if (root.right != null) {
calculate_paths(root.right);
root.R = root.right.R + 1;
}
}
int max_paths(Node root) {
int maxL = 0;
int maxR = 0;
if (root.left != null) maxL = max_paths(root.left);
if (root.right != null) maxR = max_paths(root.right);
return Math.max(Math.max(root.L, root.R), Math.max(maxL, maxR));
}
}
公共課主要{
public static void main(String[] args){
System.out.println("Let the challenge begin!");
//create the tree
Node n0 = new Node();
Node n1 = new Node();
Node n2 = new Node();
Node n3 = new Node();
Node n4 = new Node();
Node n5 = new Node();
Node n6 = new Node();
Node n7 = new Node();
Node n8 = new Node();
Node n9 = new Node();
Node n10 = new Node();
n0.right = n1;
n0.left = n7;
n1.left = n2;
n2.left = n3;
n2.right = n4;
n4.right = n5;
n5.right = n6;
n6.left = n9;
n6.right = n10;
n7.left = n8;
BTree Tree = new BTree();
Tree.calculate_paths(n0);
System.out.println(Tree.max_paths(n0));
}
}
Java實現:
// auxiliary method, starts the recursion:
public int height(){
if(root != null) // If not null calculate height
return height(root);
else // height is zero...
return 0;
}
// Gets the job done:
private int height(BinaryTreeNode<T> node){
int right = 0, left = 0;
if (node.getLeftChild() != null) // count and calculate left path height
left= 1+ height(node.getLeftChild());
if (node.getRightChild() != null) // count and calculate right path height
right= 1 + height(node.getRightChild());
return Math.max(left, right);
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.