二叉树中从源节点到目标节点的逐步最短路径
给定一个二叉树的根和两个整数startValue和destValue分别表示开始和结束节点。任务是找到从开始节点到结束节点的最短路径,并以下面给出的方向的形式打印路径。
- 从一个节点到其左子节点由字母'L'表示。
- 从一个节点到其右子节点由字母'R'表示。
- 要从一个节点导航到其父节点,请使用字母“U” 。
例子:
Input: root = [5, 1, 2, 3, null, 6, 4], startValue = 3, destValue = 6
5
/ \
1 2
/ / \
3 6 4
Output: “UURL”
Explanation: The shortest path is: 3 → 1 → 5 → 2 → 6.
Input: root = [2, 1], startValue = 2, destValue = 1
2
/
1
Output: “L”
Explanation: The shortest path is: 2 → 1.
方法:解决此问题的最简单方法是使用二叉树的 LCA(最低公共祖先)。请按照以下步骤解决给定的问题。
- 应用LCA以获得新的根。
- 从新根目录获取路径到start和dest 。
- 连接 startPath 和 destPath,并确保将 startPath 的字符替换为'U' 。
下面是上述方法的实现。
C++
// C++ program for above approach
#include
using namespace std;
// Structure of Tree
class TreeNode {
public:
int val;
TreeNode* left;
TreeNode* right;
TreeNode(int val2)
{
val = val2;
left = NULL;
right = NULL;
}
};
// Function to find LCA of two nodes
TreeNode* lca(TreeNode* root,
int startValue,
int destValue)
{
// Base Case
if (!root)
return NULL;
if (root->val == startValue)
return root;
if (root->val == destValue)
return root;
auto l = lca(root->left,
startValue, destValue);
auto r = lca(root->right,
startValue, destValue);
if (l && r)
return root;
return l ? l : r;
}
bool getPath(TreeNode* root,
int value,
string& path)
{
// Base Cases
if (!root)
return false;
if (root->val == value)
return true;
path += 'L';
auto res = getPath(root->left,
value, path);
if (res)
return true;
path.pop_back();
path += 'R';
res = getPath(root->right,
value, path);
if (res)
return true;
path.pop_back();
return false;
}
// Function to get directions
string getDirections(TreeNode* root,
int startValue,
int destValue)
{
// Find the LCA first
root = lca(root, startValue, destValue);
string p1, p2;
// Get the path
getPath(root, startValue, p1);
getPath(root, destValue, p2);
for (auto& c : p1)
c = 'U';
// Return the concatenation
return p1 + p2;
}
// Driver Code
int main()
{
/*
5
/ \
1 2
/ / \
3 6 4
*/
TreeNode* root = new TreeNode(5);
root->left = new TreeNode(1);
root->right = new TreeNode(2);
root->left->left = new TreeNode(3);
root->right->left = new TreeNode(6);
root->right->right = new TreeNode(4);
int startValue = 3;
int endValue = 6;
// Function Call
string ans = getDirections(
root, startValue, endValue);
// Print answer
cout << ans;
}
Python3
# Python program for above approach
# Structure of Tree
class TreeNode :
def __init__(self, val2):
self.val = val2;
self.left = None;
self.right = None;
# Function to find LCA of two nodes
def lca(root, startValue, destValue):
# Base Case
if (not root):
return None;
if (root.val == startValue):
return root;
if (root.val == destValue):
return root;
l = lca(root.left,
startValue, destValue);
r = lca(root.right,
startValue, destValue);
if (l and r):
return root;
return l if l else r;
def getPath(root, value, path) :
# Base Cases
if (not root):
return False;
if (root.val == value):
return True;
path.append('L');
res = getPath(root.left, value, path);
if (res):
return True;
path.pop();
path.append('R');
res = getPath(root.right, value, path);
if (res):
return True;
path.pop();
return False;
# Function to get directions
def getDirections(root, startValue, destValue) :
# Find the LCA first
root = lca(root, startValue, destValue);
p1 = []
p2 = []
# Get the path
getPath(root, startValue, p1);
getPath(root, destValue, p2);
for i in range(len(p1)):
p1[i] = 'U';
# Return the concatenation
s = ""
for i in range(len(p1)):
s += p1[i];
for i in range(len(p2)):
s += p2[i];
return s;
# Driver Code
"""
5
/ \
1 2
/ / \
3 6 4
"""
root = TreeNode(5);
root.left = TreeNode(1);
root.right = TreeNode(2);
root.left.left = TreeNode(3);
root.right.left = TreeNode(6);
root.right.right = TreeNode(4);
startValue = 3;
endValue = 6;
# Function Call
ans = getDirections(root, startValue,
endValue);
# Print answer
print(ans)
# self code is contributed by Saurabh Jaiswal
Javascript
C++
// C++ program for above approach
#include
using namespace std;
// Structure of Tree
class TreeNode {
public:
int val;
TreeNode* left;
TreeNode* right;
TreeNode(int val2)
{
val = val2;
left = NULL;
right = NULL;
}
};
// Find Function
bool find(TreeNode* n, int val,
string& path)
{
if (n->val == val)
return true;
if (n->left && find(n->left,
val, path)) {
path.push_back('L');
return true;
}
if (n->right && find(n->right,
val, path)) {
path.push_back('R');
return true;
}
return false;
}
// Function to keep track
// of directions at any point
string getDirections(TreeNode* root,
int startValue,
int destValue)
{
// To store the startPath and destPath
string s_p, d_p;
find(root, startValue, s_p);
find(root, destValue, d_p);
while (!s_p.empty() && !d_p.empty()
&& s_p.back() == d_p.back()) {
s_p.pop_back();
d_p.pop_back();
}
for (int i = 0; i < s_p.size(); i++) {
s_p[i] = 'U';
}
reverse(d_p.begin(), d_p.end());
string ans = s_p + d_p;
return ans;
}
// Driver Code
int main()
{
/*
5
/ \
1 2
/ / \
3 6 4
*/
TreeNode* root = new TreeNode(5);
root->left = new TreeNode(1);
root->right = new TreeNode(2);
root->left->left = new TreeNode(3);
root->right->left = new TreeNode(6);
root->right->right = new TreeNode(4);
int startValue = 3;
int endValue = 6;
// Function Call
string ans = getDirections(
root, startValue, endValue);
// Print the result
cout << ans;
}
UURL
时间复杂度: O(3N),因为完成了三个遍历。
辅助空间: O(1)
高效方法:此方法是基于实现的,但此方法中不使用LCA 。请按照以下步骤解决给定的问题。
- 从根开始为起点和终点建立方向。
- 假设我们得到“LLRRL”和“LRR” 。
- 删除公共前缀路径。
- 我们删除“L” ,现在开始方向是“LRRL” ,目的地 - “RR”
- 将开始方向的所有步骤替换为“U”并添加目标方向。
- 结果是“UUUU”+“RR” 。
下面是上述方法的实现。
C++
// C++ program for above approach
#include
using namespace std;
// Structure of Tree
class TreeNode {
public:
int val;
TreeNode* left;
TreeNode* right;
TreeNode(int val2)
{
val = val2;
left = NULL;
right = NULL;
}
};
// Find Function
bool find(TreeNode* n, int val,
string& path)
{
if (n->val == val)
return true;
if (n->left && find(n->left,
val, path)) {
path.push_back('L');
return true;
}
if (n->right && find(n->right,
val, path)) {
path.push_back('R');
return true;
}
return false;
}
// Function to keep track
// of directions at any point
string getDirections(TreeNode* root,
int startValue,
int destValue)
{
// To store the startPath and destPath
string s_p, d_p;
find(root, startValue, s_p);
find(root, destValue, d_p);
while (!s_p.empty() && !d_p.empty()
&& s_p.back() == d_p.back()) {
s_p.pop_back();
d_p.pop_back();
}
for (int i = 0; i < s_p.size(); i++) {
s_p[i] = 'U';
}
reverse(d_p.begin(), d_p.end());
string ans = s_p + d_p;
return ans;
}
// Driver Code
int main()
{
/*
5
/ \
1 2
/ / \
3 6 4
*/
TreeNode* root = new TreeNode(5);
root->left = new TreeNode(1);
root->right = new TreeNode(2);
root->left->left = new TreeNode(3);
root->right->left = new TreeNode(6);
root->right->right = new TreeNode(4);
int startValue = 3;
int endValue = 6;
// Function Call
string ans = getDirections(
root, startValue, endValue);
// Print the result
cout << ans;
}
UURL
时间复杂度: O(N)
辅助空间: O(1),如果忽略则递归堆栈空间。