2020-07-11【樹】

等待那一束光

今日雞湯:

大腦的一切疲勞和壓力來(lái)自于過(guò)去和未來(lái):對(duì)已經(jīng)發(fā)生的事情心有不甘,對(duì)將要發(fā)生的事情充滿不安。

愿你內(nèi)心平和肯污,踏踏實(shí)實(shí)活在當(dāng)下,不去悔恨過(guò)去吨枉,不去憂心未來(lái)仇箱。

今天一起來(lái)看樹啦,多刷題东羹,多刷題,有助于預(yù)防老年癡呆忠烛。

樹的基礎(chǔ)

1. 樹的最大深度

最大深度一定是到葉子節(jié)點(diǎn)了才能判斷是不是最深属提,為了記錄層數(shù),可以在遍歷樹的時(shí)候定義新的數(shù)據(jù)結(jié)構(gòu)美尸,另外存下來(lái)當(dāng)前節(jié)點(diǎn)的層信息冤议,這樣訪問(wèn)葉子節(jié)點(diǎn)時(shí),只要取出來(lái)判斷一下就可以了师坎。

    class NodeLevel{
        TreeNode node;
        int level;
         
        NodeLevel(TreeNode node,int level){
            this.node = node;
            this.level = level;
        }
    };
    /**
     *
     * @param root TreeNode類
     * @return int整型
     */
    public int maxDepth (TreeNode root) {
        // write code here
        if(root == null)    return 0;
        return maxTreeDepth(root);
    }
     
    public int maxTreeDepth(TreeNode root){
        int maxDepthVal = 0;
        Stack<NodeLevel> parentStack = new Stack<NodeLevel>();
        Stack<NodeLevel> childrenStack = new Stack<NodeLevel>();
         
        // Add root to childrend stack
        childrenStack.push(new NodeLevel(root, 1));
        while(childrenStack.size() > 0){
            // Get current top node.
            NodeLevel topNode = childrenStack.pop();
            int currentLevel = topNode.level;
            if(topNode.node.right == null && topNode.node.left == null){
                if(currentLevel > maxDepthVal)    maxDepthVal = currentLevel;
            } else{
                // Add child nodes.
                if(topNode.node.left != null){
                    childrenStack.add(new NodeLevel(topNode.node.left, currentLevel + 1));
                } 
                if(topNode.node.right != null){
                    childrenStack.add(new NodeLevel(topNode.node.right, currentLevel + 1));
                }
            }
            parentStack.push(topNode);
        }
        return maxDepthVal;
    }

樹的遍歷

先來(lái)看樹的遍歷恕酸。主要分為前序(先序)、中序和后序胯陋,遍歷方法也很直接蕊温,遞歸和非遞歸袱箱,遞歸比較簡(jiǎn)單,主要看一下非遞歸方式义矛,涉及到不同的數(shù)據(jù)結(jié)構(gòu)发笔。

1. 前序遍歷

前序遍歷是按照<根、左凉翻、右>的方式來(lái)遍歷了讨,特點(diǎn)是根先出,所以可以用一個(gè)棧+一個(gè)隊(duì)列的數(shù)據(jù)結(jié)構(gòu)制轰。棧用來(lái)存當(dāng)前節(jié)點(diǎn)前计,隊(duì)列用來(lái)按順序存放遍歷結(jié)果。注意壓棧是要先右再左垃杖,這樣出棧時(shí)才是先左后右男杈。

public ArrayList<Integer> preorderTraversal (TreeNode root) {
        Stack<TreeNode> stack = new Stack<TreeNode>();
        ArrayList<Integer> preOrderList = new ArrayList<Integer>();
        
        if(root == null)    return preOrderList;
        // Add root to stack
        stack.push(root);
        
        while(stack.size() != 0){
            // Get top node and put it into list.
            TreeNode topNode = stack.pop();
            preOrderList.add(topNode.val);
            
            // Push right node and left node to stack.
            if(topNode.right != null){
                stack.push(topNode.right);
            }
            if(topNode.left != null){
                stack.push(topNode.left);
            }
        }
        return preOrderList;
    }

2. 中序遍歷

中序遍歷是按照<左、中缩滨、右>的方式遍歷势就,特點(diǎn)是根在中間,可以根據(jù)根節(jié)點(diǎn)位置直接區(qū)分左右子樹的元素脉漏。因此苞冯,可以用一個(gè)棧,直接DFS侧巨,一直找左節(jié)點(diǎn)舅锄,為空時(shí)出棧,再加入右節(jié)點(diǎn)司忱。

public ArrayList<Integer> inorderTraversal (TreeNode root) {
        ArrayList<Integer> traversalList = new ArrayList<Integer>();
         
        Stack<TreeNode> stack = new Stack<TreeNode>();
         
        TreeNode currentNode = root;
        // When all nodes are processed,  stack will be empty, stop the loop.
        while(currentNode != null || !stack.isEmpty()){
            if(currentNode != null){
                // Push left node to the stack
                stack.push(currentNode);
                currentNode = currentNode.left;
            } else{
                // Pop current node in the stack
                TreeNode popedNode = stack.pop();
                // Add value to list
                traversalList.add(popedNode.val);
                // Push right node
                currentNode = popedNode.right;
            }
        }
        return traversalList;
    }

3. 后序遍歷

后序遍歷是按照<左皇忿、右、中>的方式遍歷坦仍,特點(diǎn)是根節(jié)點(diǎn)在最后鳍烁,因此用兩個(gè)棧,一個(gè)存放當(dāng)前節(jié)點(diǎn)繁扎,一個(gè)存放當(dāng)前節(jié)點(diǎn)的左右孩子幔荒。注意壓棧時(shí)先左后右。

public ArrayList<Integer> postorderTraversal (TreeNode root) {
        // write code here
        ArrayList<Integer> postorderList = new ArrayList<Integer>();
        if(root == null)    return postorderList;
         
        Stack<TreeNode> parentStack = new Stack<TreeNode>();
        Stack<TreeNode> childrenStack = new Stack<TreeNode>();
         
        // Put root into children stack.
        childrenStack.push(root);
         
        while(childrenStack.size() != 0){
            // Pop top node and push it into parent stack.
            TreeNode topNode = childrenStack.pop();
            parentStack.push(topNode);
             
            // Push left and right node into children stack.
            if(topNode.left != null){
                childrenStack.push(topNode.left);
            }
            if(topNode.right != null){
                childrenStack.push(topNode.right);
            }
        }
         
        // Pop element in parent stack and save it into list.
        while(parentStack.size() != 0){
            postorderList.add(parentStack.pop().val);
        }
        return postorderList;
    }

4. 層次遍歷(分層存儲(chǔ))

層次遍歷是一層一層的從左往右遍歷梳玫,遇到空節(jié)點(diǎn)直接跳過(guò)爹梁,所以可以用兩個(gè)隊(duì)列,一個(gè)隊(duì)列放該層的節(jié)點(diǎn)提澎,一個(gè)隊(duì)列放上個(gè)隊(duì)列所有節(jié)點(diǎn)的孩子姚垃,再倒手。

    public ArrayList<ArrayList<Integer>> levelOrder (TreeNode root) {
        // write code here
        ArrayList<ArrayList<Integer>> orderTraverseList = new ArrayList<ArrayList<Integer>>();
         
        if(root == null)    return orderTraverseList;
         
        ArrayList<TreeNode> parentList = new ArrayList<TreeNode>();
 
        parentList.add(root);
        
        while(parentList != null && parentList.size() != 0){
            // Add parent node list
            orderTraverseList.add(generateVal(parentList));
            // Generate children node list
            ArrayList<TreeNode> childrenList = generateChildren(parentList);
            //orderTraverseList.add(generateVal(childrenList));
            parentList = childrenList;
        } 
        return orderTraverseList;
    }
     
    public ArrayList<Integer> generateVal(ArrayList<TreeNode> nodeList){
        ArrayList<Integer> valList = new ArrayList<Integer>();
        for(TreeNode node: nodeList){
            valList.add(node.val);
        }
        return valList;
    }
     
    public ArrayList<TreeNode> generateChildren(ArrayList<TreeNode> parentList){
        ArrayList<TreeNode> childrenList = new ArrayList<TreeNode>();
        // Pop nodes in list and save them to current level list.
        for(TreeNode node: parentList){
            // Save all children of nodes in queue1 to queue2
            if(node.left != null){
                childrenList.add(node.left);
            }
            if(node.right != null){
                childrenList.add(node.right);
            }
        }
        return childrenList;
    }

各種奇葩的??

1. 判斷是不是平衡二叉樹

平衡二叉樹就是每個(gè)節(jié)點(diǎn)左右子樹高度差絕對(duì)值不超過(guò)1的二叉樹盼忌,因此先遞歸計(jì)算左右子樹的高度积糯,再判斷當(dāng)前節(jié)點(diǎn)左右子樹高度差是否滿足條件掂墓,若滿足,再對(duì)左右子樹的結(jié)果做與運(yùn)算即可絮宁。

public boolean isBalanced (TreeNode root) {
        // write code here
        if(root == null)    return true;
        int leftTreeHeight = getHeight(root.left);
        int rightTreeHeight = getHeight(root.right);
        if(Math.abs(leftTreeHeight - rightTreeHeight) <= 1){
            return isBalanced(root.left) && isBalanced(root.right);
        }
        return false;
    }
     
    public int getHeight(TreeNode root){
        if(root == null)    return 0;
        int left = getHeight(root.left) + 1;
        int right = getHeight(root.right) + 1;
        return (left > right) ? left: right;
    }
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末梆暮,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子绍昂,更是在濱河造成了極大的恐慌啦粹,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,270評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件窘游,死亡現(xiàn)場(chǎng)離奇詭異唠椭,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)忍饰,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,489評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門贪嫂,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人艾蓝,你說(shuō)我怎么就攤上這事力崇。” “怎么了赢织?”我有些...
    開封第一講書人閱讀 165,630評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵亮靴,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我于置,道長(zhǎng)茧吊,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,906評(píng)論 1 295
  • 正文 為了忘掉前任八毯,我火速辦了婚禮搓侄,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘话速。我一直安慰自己讶踪,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,928評(píng)論 6 392
  • 文/花漫 我一把揭開白布泊交。 她就那樣靜靜地躺著俊柔,像睡著了一般。 火紅的嫁衣襯著肌膚如雪活合。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,718評(píng)論 1 305
  • 那天物赶,我揣著相機(jī)與錄音白指,去河邊找鬼。 笑死酵紫,一個(gè)胖子當(dāng)著我的面吹牛告嘲,可吹牛的內(nèi)容都是我干的错维。 我是一名探鬼主播,決...
    沈念sama閱讀 40,442評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼橄唬,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼赋焕!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起仰楚,我...
    開封第一講書人閱讀 39,345評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤隆判,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后僧界,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體侨嘀,經(jīng)...
    沈念sama閱讀 45,802評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,984評(píng)論 3 337
  • 正文 我和宋清朗相戀三年捂襟,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了咬腕。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,117評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡葬荷,死狀恐怖涨共,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情宠漩,我是刑警寧澤举反,帶...
    沈念sama閱讀 35,810評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站哄孤,受9級(jí)特大地震影響照筑,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜瘦陈,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,462評(píng)論 3 331
  • 文/蒙蒙 一凝危、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧晨逝,春花似錦蛾默、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,011評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至趁窃,卻和暖如春牧挣,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背醒陆。 一陣腳步聲響...
    開封第一講書人閱讀 33,139評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工瀑构, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人刨摩。 一個(gè)月前我還...
    沈念sama閱讀 48,377評(píng)論 3 373
  • 正文 我出身青樓寺晌,卻偏偏與公主長(zhǎng)得像世吨,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子呻征,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,060評(píng)論 2 355