劍指Offer(Java版):二叉樹中和爲某一值的路徑

題目:輸入一顆二叉樹和一個整數,打印出二叉樹中結點值的和爲輸入整數的全部路徑。從樹的根節點開始往下一直到葉結點所通過的全部的結點造成一條路徑。java

以下圖,輸入二叉樹和整數22,則打印出兩條路徑,第一條路徑包含結點10,12,第二條路徑包含的結點爲10,5,7.node

通常的數據結構和算法的教材都沒有介紹樹的路徑,所以對大多數應聘者而言,這是一個新概念,也就很難一會兒想出完整的解題思路。這個時候咱們能夠試着從一兩個具體的例子入手,找到規律。算法

以圖中的二叉樹爲例分析,因爲路徑是從根節點出發到葉結點,也就是說路徑是以根節點爲起始點,所以i咱們首先須要遍歷根節點。在樹的前序、中序、後序三種遍歷方式中,只有前序遍歷是首先訪問根節點的。數據結構

按照前序遍歷的順序遍歷途中的二叉樹,在訪問結點10以後,就會訪問結點5.從二叉樹結點的定義能夠看出,在本題的二叉樹結點中沒有指向父節點的指針,訪問到結點5的時候,咱們是不知道前面通過了哪些結點的,除非咱們把通過的路徑上的結點都保存起來。每訪問到一個結點的時候,咱們都把當前的結點添加到路徑中去。到達結點5時,路徑中包含兩個結點,他們的值分別是10和5.接下來遍歷到結點4,咱們把這個結點也添加到路徑中,這個時候已經到達了葉結點,但路徑上三個結點的值之和爲19.這個和不等於輸入的值22,所以不符合要求的路徑。數據結構和算法

咱們接着要遍歷其餘的結點。在遍歷下一個節點以前,先要從結點4回到結點5,再去遍歷結點5的右子節點7.值得注意的是,回到結點5的時候,因爲結點4已經不在前往結點7的路徑上了,咱們須要把結點4從路徑中刪除。接下來訪問到結點7的時候,再把結點添加到路徑中。此時路徑中三個結點10,5,7之和恰好是22,是一條符合要求的路徑。函數

咱們最後要遍歷的結點是12.在遍歷這個結點以前,須要先通過結點5回到結點10.一樣,每一次當從子節點回到父節點的時候,咱們都須要在路徑上刪除子節點。最後從結點10到達結點12的時候,路徑上的兩個結點的值之和也是22,所以這也是一條符合條件的路徑。.net

總結過程以下:指針

分析完前面的具體的例子以後,咱們就找到了一些規律。當用前序遍歷的方式訪問到某一節點時,咱們把該結點添加到路徑上,並累加該結點的值。若是該結點爲葉結點而且路徑中結點值的和恰好爲輸入的整數,則當前的路徑符合要求,咱們把它打印出來。若是當前的結點不是葉結點,則繼續訪問它的子節點。當前結點訪問結束後,遞歸函數將自動回到它的父節點。所以咱們在函數退出以前要在路徑上刪除當前結點並減去當前結點的值,以確保返回父節點時路徑恰好是從根節點到父節點的路徑。咱們不難看出保存路徑的數據結構其實是一個棧,所以路徑要與遞歸調用狀態一致,而遞歸調用的本質上是一個壓棧和出棧的過程。遞歸

Java代碼實現:get

package cglib;

import java.util.Stack;

class BinaryTreeNode{
    int value;
    BinaryTreeNode leftNode;
    BinaryTreeNode rightNode;
    
    

}

public class DeleteNode {
    public  void findPath(BinaryTreeNode root,int sum){
        if(root==null)
        return;
        Stack<Integer> stack=new Stack<Integer>();
        int currentSum=0;
        findPathd(root,sum,stack,currentSum);
        }
        private  void findPathd(BinaryTreeNode root, int sum, Stack<Integer> stack,int currentSum) {
        System.out.println("根結點值"+root.value);
        currentSum+=root.value;
        stack.push(root.value);
        if(root.leftNode==null&&root.rightNode==null){
        if(currentSum==sum){
        System.out.println("找到一個路徑");
        for(int path:stack){
        System.out.print(path+" ");
        }
        System.out.println();
        }
        }
        if(root.leftNode!=null){
            System.out.println("左結點值"+root.leftNode.value);
        findPathd(root.leftNode, sum, stack, currentSum);
        }
        if(root.rightNode!=null){
            System.out.println("右結點值"+root.leftNode.value);
        findPathd(root.rightNode, sum, stack, currentSum);
        }
        int t=stack.pop();
        System.out.println("出棧值="+t);
        }
    public static void main(String[] args) throws Exception{  
        BinaryTreeNode root1=new BinaryTreeNode();
        BinaryTreeNode node1=new BinaryTreeNode();
        BinaryTreeNode node2=new BinaryTreeNode();
        BinaryTreeNode node3=new BinaryTreeNode();
        BinaryTreeNode node4=new BinaryTreeNode();
        root1.leftNode=node1;
        root1.rightNode=node2;
        node1.leftNode=node3;
        node1.rightNode=node4;
        root1.value=10;
        node1.value=5;
        node2.value=12;
        node3.value=4;
        node4.value=7;
        DeleteNode testFindPath=new DeleteNode();
        testFindPath.findPath(root1, 22);
        }
        
    } 

 

輸出:

根結點值10 左結點值5 根結點值5 左結點值4 根結點值4 出棧值=4 右結點值4 根結點值7 找到一個路徑 10 5 7 出棧值=7 出棧值=5 右結點值5 根結點值12 找到一個路徑 10 12 出棧值=12 出棧值=10

相關文章
相關標籤/搜索