轉自https://blog.csdn.net/innovate1989/article/details/73350400
參考liuyi1207164339帖子和ethannnli的帖子的基礎上搞定了這個問題。剛開始頭真的大了,感覺有點超出能力范圍了。分析了他們的思路,求解這個二叉樹中兩節點的最短路徑這個問題可以分解為三個子問題:1.求出二叉樹中兩個節點p和q的最小公共祖先 2.分別求出最小公共祖先節點到p和q的路徑 3.歸並求出的兩條路徑
問題1求解可以參考:https://segmentfault.com/a/1190000003509399,ethannnli 采用了二分法和深度搜索兩種方法求解。
問題2求解可以參考:http://blog.csdn.net/liuyi1207164339/article/details/50916687,采用深度搜索求出lca到p或者q的路徑。
問題3求解比較簡單,我是直接通過對前兩步返回的字符串進行后處理。
以如下二叉樹作為測試二叉樹:
public class FindShortestPath {
//查找指定節點的標記
boolean bLeafIsFound = false;
String path1;
public String findPath(TreeNode root, Stack<Integer> path, TreeNode nodeToFind){
if (root == null) {
return null;
}
//將路徑節點添加到棧中
path.push(root.val);
//如果到達了子節點
if (!bLeafIsFound && root.val == nodeToFind.val) {
//打印路徑
path1 = printPath(path);
bLeafIsFound = true;
return path1;
}
//查詢左子樹
if (!bLeafIsFound && root.left != null) {
findPath(root.left,path, nodeToFind);
}
//查詢右子樹
if (!bLeafIsFound && root.right != null) {
findPath(root.right, path, nodeToFind);
}
//如果沒找到則彈棧
if (!bLeafIsFound) {
path.pop();
}
return path1 == null ? null : path1;
}
public String printPath(Stack<Integer> path){
int len = path.size();
String s = ""+ path.pop();
for (int i = 1; i < len; i++) {
if (path.peek() != null) {
s += "->" + path.pop();
}
}
System.out.println(s);
return s;
}
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q){
//發現目標節點則通過返回值標記該子樹發現了某個目標節點
if (root == null || root == p || root == q) {
return root;
}
//查看左子樹中是否有目標節點,沒有為null
TreeNode left = lowestCommonAncestor(root.left, p, q);
//查看右子樹中是否有目標節點,沒有為null
TreeNode right = lowestCommonAncestor(root.right, p, q);
//都不為空,則說明左右子樹都有目標節點,則公共祖先就是本身。
if (left != null && right != null) {
return root;
}
return left == null ? right : left;
}
public void findPathOfTwoNode(TreeNode root,TreeNode p, TreeNode q){
Stack<Integer> path1 = new Stack<Integer>();
Stack<Integer> path2 = new Stack<Integer>();
//尋找兩個路徑的交點,即最小公共祖先
TreeNode lca = lowestCommonAncestor(root, p, q);
//得到p節點的路徑
System.out.println("最小公共祖先節點" + lca.val + "和節點" + p.val + "之間的路徑");
String s1 = findPath(lca, path1, p);
bLeafIsFound = false;//全局變量復位
//得到q節點的路徑
System.out.println("最小公共祖先節點" + lca.val + "和節點" + q.val + "之間的路徑");
String s2 = findPath(lca, path2, q);
bLeafIsFound = false;//全局變量復位
//合並兩條路徑去掉重復的最小公共祖先
String[] split = s2.split("->");
String s3 = s1 + "->" + split[0];
for (int i = 1; i < split.length; i++) {
if (Integer.parseInt(split[i]) != lca.val) {
s3 +="->" + split[i];
}
}
System.out.println("歸並后的路徑為:" + s3);
}
public static void main(String[] args) {
TreeNode node1 = new TreeNode(1);
TreeNode node2 = new TreeNode(2);
TreeNode node3 = new TreeNode(3);
TreeNode node4 = new TreeNode(4);
TreeNode node5 = new TreeNode(5);
TreeNode node6 = new TreeNode(6);
TreeNode node7 = new TreeNode(7);
TreeNode node8 = new TreeNode(8);
node1.left = node2;
node1.right = node3;
node2.left = node4;
node3.left = node5;
node3.right = node6;
node4.right = node7;
node6.left = node8;
FindShortestPath findShortestPath = new FindShortestPath();
findShortestPath.findPathOfTwoNode(node1, node7, node3);
}
}
我使用節點7和節點3作為p和q,測試結果如下:
結果沒有什么問題,剛開始學習算法,肯定存在很多不足之處,希望大家多提意見,共同進步!
————————————————
版權聲明:本文為CSDN博主「innovate1989」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/innovate1989/article/details/73350400