1. 程式人生 > >二叉樹常見問題整理

二叉樹常見問題整理

做leetcode二叉樹的題目做了不少,覺得有必要總結一下。因為題型多歸多,但其實無非就是dfs和bfs,總結一些常見的解法,對於加深這兩週演算法的理解很有幫助。
在做dfs的時候,主要思路是可以從上到下也可以從下到上,也就是分析每一個子樹的根節點,然後分析該子樹的內部子樹或者外部子樹的根節點,以此得出遞迴關係,也即是分治的思想。同時,對於每個節點的處理嘗試利用前序、後序、中序遍歷三種方法。
做bfs的時候,主要思路是從上到下,一層一層進行分析。

構建二叉樹

leetcode 105和106題

1、利用前序和中序遍歷構建二叉樹。
構建一棵二叉樹,如果是通過dfs的方式的話,那麼分析每一個子樹的根節點,將一個大子樹分解成一個一個小的子樹,分治下去,也就可以得出遞迴。
比如,有前序1,2,4,5,3,中序4,2,5,1,3。從前序中,我們可以得出一個條件:當前子樹的根節點。
對於整個子樹1,2,4,5,3,可以確定,1是該子樹根節點,然後去中序中找1,1的左邊是4,2,5,右邊是3。因為中序的性質是在遍歷完左子樹後遍歷當前根節點,所以說4,2,5就是1為父節點的一個新的子樹。去前序中得到一個新的前序+中序陣列對:2,4,5; 4,2,5,同理,2是該子樹根節點,4是左子樹,5在右子樹, 以此類推分治遞迴下去。找到遞迴關係後,每一層根節點完成當前任務,然後將構建子樹的任務交給左右子樹遞迴過程即可。

同時,我們思考的過程是從上到下,但程式遞迴執行的過程是從下到上,這點需要注意。可以寫出程式碼:

TreeNode buildTree(int[] preorder, int[] inorder) {
        if (preorder.length != inorder.length) return null;
        if (preorder.length ==0) return null;
        //完成當前任務,構建當前子樹根節點。
        TreeNode node = new TreeNode(preorder[0]);
        if (preorder.length
== 1) return node; int root = preorder[0]; int leftCount=0; //找到根節點位置 for (int i =0;i<inorder.length;i++) { if (inorder[i] == root){ leftCount = i; break; } } //將新的構建任務遞迴交下去。 node.left = buildTree(Arrays.copyOfRange(preorder, 1
, leftCount+1),Arrays.copyOfRange(inorder,0,leftCount)); node.right = buildTree(Arrays.copyOfRange(preorder, leftCount + 1, preorder.length ), Arrays.copyOfRange(inorder, leftCount + 1, inorder.length )); return node; }

2、利用後序和中序構建二叉樹。
思路類似,還是先找根節點!可以看到,當前整個子樹根節點可以通過後續確定,然後利用中序確定左右子樹來分治遞迴。思路類似。

構建二叉搜尋樹 BST

leetcode 108和109題

1、通過有序陣列來構建一棵平衡二叉搜尋樹。

首先,對於一個有序陣列,比如1,2,3,4,5,6。這裡採用dfs解題。前面說過分析dfs時針對每一個子樹的根節點,通過各個子樹的根節點來尋找遞迴關係。
對於BST最上面的子樹,根節點就是有序陣列最中間的元素,令s = 0,e = 5,那麼mid = s +(e-s)/2 = 2。也就是3是整個子樹根節點,1,2是左子樹內容,4,5,6是右子樹內容。對於1,2有s = 0,e = 1,同理mid = 0,也就是1是該子樹根節點,2是右子樹內容。 以此類推很容易寫出遞迴:

    TreeNode dfs(int s,int e,int[] nums){
        if(s > e) return null;
        int mid = s + (e-s)/2;
        TreeNode root = new TreeNode(nums[mid]);
        root.left = dfs(s,mid-1,nums);
        root.right = dfs(mid+1,e,nums);
        return root;
    }

這裡,建議畫出遞迴棧,方便理解。在思考遞迴時,是從上到下思考,由整體到區域性,但是程式執行時從下到上的,也就是dfs執行方式。是通過前序遍歷的方式,在陣列中依次拿出2,1,3,4,5,從下到上構建出BST,構建順序是dfs的前序方式。

2、通過有序連結串列來構建一棵平衡二叉搜尋樹。
連結串列和陣列不同了,陣列可以隨機訪問,而連結串列只能順序訪問。所以,我們的思路應該是,依次將1,2,3,4,5填到BST的正確位置。利用類似1中的dfs,可以得到下圖的遞迴棧,也就是說這5個符合條件的點就是BST中的點。我們從連結串列中依次拿出1,2,3,4,5,填入到這個樹結構並構造BST。可以看到,對於1,應該填在0->1的位置,2填在1->1的位置,然後3填在0->4,4填在3->4,其實也就是以中序遍歷的順序填進去。這樣一來,程式碼也就出來了:
這裡寫圖片描述

    TreeNode dfs(int s, int e) {
        if (s > e) return null;
        int mid = s + (e -s )/2;
        TreeNode left = dfs(s, mid - 1);
        TreeNode node = new TreeNode(head.val);
        head = head.next;
        TreeNode right = dfs(mid + 1, e);
        node.left = left;
        node.right = right;
        return node;
    }

可以看到,在構建樹或者BST的過程中,找準根節點位置以及填放順序,來相應處理即可。

按層級遍歷問題

leetcode 102,103,107都是此類問題,此類問題十分簡單,可以採用bfs和dfs求解。

將一棵二叉樹按層級遍歷。
這裡寫圖片描述
如果使用bfs,遍歷完一層後可以得到下一次的全部節點數,在每一次遍歷後一次性遍歷整個一層即可。
程式碼類似:

    Queue<TreeNode> queue = new LinkedList<>();
    queue.add(root);
    while(!queue.isEmpty()){
        int size = queue.size();
        //利用for迴圈,一次性遍歷一個層級。
        for(int i = 0;i<size;i++){
            TreeNode cur = queue.poll();
            queue.add(cur.left);
            queue.add(cur.right);
        }
    }

如果使用dfs,我們無法保證一個層級的全部節點是同一時刻遍歷的,但是可以分時遍歷,也就是在dfs中新增一個關於level的引數,將同一level的點加入到結果中。

    dfs(TreeNode root,int level){
        if(root == null ) return;
        //將當前節點新增到結果中
        result.get(level).add(root);
        dfs(root.left,level+1);
        dfs(root.right,level + 1);
    }

可以看到,利用level將節點新增到結果連結串列相應位置,不管是正序,倒敘還是ZigZag,都是相應計算的事,所以還是比較推薦dfs,簡單整潔。

相關推薦

常見問題整理

做leetcode二叉樹的題目做了不少,覺得有必要總結一下。因為題型多歸多,但其實無非就是dfs和bfs,總結一些常見的解法,對於加深這兩週演算法的理解很有幫助。 在做dfs的時候,主要思路是可以從上到下也可以從下到上,也就是分析每一個子樹的根節點,然後分析該

常見題目

dep height tree right pre 個數 二叉樹 節點 leaf 一、求二叉樹的最大深度 public int maxDepth(Node node){ if(node == null) return 0; int left

常見問題

1.兩顆二叉樹A和B,判斷B是不是A的子結構 /* 思路:1.在樹A中找到和B的根節點一樣的節點R 2.判斷樹A以R為根節點的子樹是不是包含和樹B一樣的結構 */ bool DoesTree1HaveTree2(BiTreeNode*T1,BiTreeNode*T2); boo

常見演算法總結-基本

二叉樹是最經典的資料結構之一,其結構型別和演算法操作也是十分多,今天來做一個總結(今天先不討論對B樹,紅黑樹那種比較高階的資料結構)。 樹結構,一般用節點引用兩個子節點作為左右節點。結構程式碼如下 PS:有些時候也要有個指

演算法整理

演算法1, 序列化二叉樹(二叉樹的先序遍歷) class TreeNode: def __init__(self, x): self.val = x self.left = None self.right = None clas

紅黑( 尚未整理 )

標頭檔案:#ifndef __AOS_RBTREE_H__ #define __AOS_RBTREE_H__ typedef enum aos_rbcolor_t { AOS_RBCOLOR_BLACK, AOS_RBCOLOR_RED } AOS_RBCO

鏈表,相關算法的簡單整理

kmp 誰的 指針 感覺 它的 左右子樹 排序 原理 鏡像 最近在刷牛客網的劍指offer的題,感覺自己的編程能力還是很差,有時候有思路但是總是需要調試蠻久的時間,但是練習的太少。 鏈表 A->B->C->D 簡單的說單鏈表就是一個當前的節點只指向鏈表

常見建立和遍歷

#include <stdio.h> #include <stdlib.h>> const int MAX=20; typedef struct Node { char data; struct Node*lchild; struct Node*rchild

習題整理後續遍歷得到指定節點到其祖先的路徑

src 圖片 image 整理 遍歷 .com http 得到 jpg 習題整理,二叉樹後續遍歷得到指定節點到其祖先的路徑

的儲存表示與實現(陳銳,葛麗萍跟我學資料結構整理

1.二叉樹的順序儲存, 即用一維陣列按照從左到右,從上到下的順序依次儲存,分析計算可得每個節點的編號,類似於樹狀陣列。 適用於完全二叉樹。 儲存非完全二叉樹時,需要在一維陣列中將二叉樹不存在的結點位置空出,並用NULL填充。 2.二叉樹.的鏈式儲存 二叉樹的鏈式儲存結構 二叉

常見演算法

1.二叉樹的遍歷演算法 二叉樹的遍歷主要分為三種:先序遍歷,中序遍歷和後序遍歷。還有一種就是按照層次遍歷。 按照慣例,左孩子優先於右孩子,那麼: 先序遍歷指的就是先訪問本節點,再訪問該節點的左孩子和右孩子; 中序遍歷指的就是:先訪問左孩子,再訪問本節點,最後訪問右孩子; 後

面試題目整理--20181109--中序遍歷非遞迴實現

非遞迴實現二叉樹的中序遍歷 首先看一下遞迴方式的實現方式: class TreeNode: left = None right = None var = 0 def __init__(self, var): self.var

資料結構知識整理 - 遍歷的應用

主要內容 建立二叉連結串列 複製二叉樹 計算二叉樹深度 統計二叉樹的結點個數   建立二叉連結串列 在先序遍歷的遞迴演算法中,將輸出語句改為輸入語句即可。(可回顧“遞迴演算法”) 需要注意的是,遞迴演算法會遍歷滿二叉樹中的每一個結點,

的定義、性質及常見

滿足以下兩個條件的樹形結構叫做二叉樹 1.每個結點的度都不大於2 2.每個結點的孩子次序不能顛倒 性質 在二叉樹的第i層上至多有2^(i-1)個結點 深度為k的二叉樹上至多有2^k-1個結點 對任何一棵二叉樹,若它含有n0 個葉子結點、n2 個度為

資料結構中常見(BST搜尋、AVL平衡、RBT紅黑、B-、B+、B*

BST樹 即二叉搜尋樹:        1.所有非葉子結點至多擁有兩個兒子(Left和Right);        2.所有結點儲存一個關鍵字;        3.非葉子結點的左指標指向小於其關鍵字的子樹,右指標指向大於其關鍵字的子樹; 如:      

資料結構知識整理 - 平衡

平衡二叉樹(Balanced Binary Tree) 平衡二叉樹是由一般的二叉排序樹經過平衡調整得到的,每個結點的左右子樹深度差小於等於1的特殊的二叉排序樹。 已經提到,二叉排序樹的平均查詢長度與它的形態有關,其中平衡二叉樹就是一種最好的形態。 特徵: 1)左右子樹深度差的絕對

遞迴非遞迴遍歷,層次遍歷,反轉,輸出路徑等常見操作詳細總結

1.序言 在實際工作中,很多業務場景其實也需要一些比較巧妙的演算法來支撐,並不是業務邏輯就全是複製貼上或者說重複的程式碼寫一百遍。越是隨著演算法研究的深入,越是發現數據結構的重要性。或者說,資料結構中就蘊藏著無數精妙演算法的思想,很多演算法的思想在資料結構中體現得非常突出。而作為一種

常見方法及三種遍歷方式 Java 實現

讀完本文你將瞭解到: 樹的分類有很多種,但基本都是 二叉樹 的衍生,今天來學習下二叉樹。 什麼是二叉樹 Binary Tree 先來個定義: 二叉樹是有限個節點的集合,這個集合可以是空集,也可以是一個根節點和至多兩個子二叉樹組成的集合,其中一顆樹叫做根的左子樹,另一棵叫做根的右子樹。

常見筆試面試題

在二叉樹的基本操作裡已經說明如何用遞迴的方法進行二叉樹的遍歷,那麼如何用非遞迴的方法來進行二叉樹的遍歷呢,請看下文1.使用非遞迴方式進行二叉樹的先序遍歷思想:先將根節點入棧然後出棧,繼續將右子樹先入棧,然後將左子樹入棧,因為棧是先進後出的原則,所以左子樹後進是先出來的實現程式

整理五道演算法題系列(1)相關

背景 最近想整理一些有意思的題目,特別是給力的破題技巧與思想,均為學習筆記,於此做個長期記錄。不多說,進入演算法世界了~~ 說明 => 五道 / 篇 => Java => 二叉樹相關 題目 1、重建二叉樹 輸入某二叉