劍指offer 二叉樹專題

二叉樹的定義及相關性質

二叉樹性質及操作

注意:對于String來說,length()是一個方法诗祸,必須加括號
而對于數(shù)組來說屹培,length只是數(shù)組的父類Array從Object哪里繼承過來的屬性,所以是類的屬性沟绪,就不需要加括號

劍指offer 07 重建二叉樹

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    int[] preorder;
    HashMap<Integer, Integer> dic = new HashMap<>();

    public TreeNode buildTree(int[] preorder, int[] inorder) {
        this.preorder = preorder;   //將preorder 變成全局變量刮便, recur中可直接調用

        //將inorder裝入HashMap中,方便后面查找root
        for(int i=0; i<inorder.length; i++){
            dic.put(inorder[i],i);
        }
        return recur(0,0,inorder.length - 1);
    }
    /**
    * 利用inorder的最左和最右node分別在list中的第一和最后一個绽慈,不斷地迭代遍歷整個樹
    * @param root_preIndx root在preorder中的index
    * @param left_inIndx  整個樹的最左node在inorder中的index
    * @param right_inIndx 整個樹的最右node在inorder中的index
    * @return 當前樹的root
    */
    public TreeNode recur (int root_preIndx, int left_inIndx, int right_inIndx){
        //當最左node的index大于最右node的index恨旱, 即已經遍歷完
        if(left_inIndx > right_inIndx){
            return null; 
        }

        TreeNode node = new TreeNode(preorder[root_preIndx]);
        int root_inIndx = dic.get(preorder[root_preIndx]);  //查詢root在inorder中的index
        //node.left = 左子樹的root
        node.left = recur(root_preIndx + 1, left_inIndx, root_inIndx - 1);

        //求出左子樹在inorder中長度len_left辈毯,node.right在preorder中的index = root_preIndx + len_left
        int len_left = root_inIndx - left_inIndx + 1;
        node.right = recur(root_preIndx + len_left, root_inIndx + 1, right_inIndx);

        return node;
    }
}

劍指offer 26 樹的子結構
若樹B是樹A的子結構,樹A節(jié)點為M搜贤,樹B節(jié)點為N谆沃, 則
時間復雜度O(MN)
空間復雜度O(M)

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public boolean isSubStructure(TreeNode A, TreeNode B) {
        if (A == null || B == null) return false;
        if (treeCompare(A,B)) return true;
        else return isSubStructure(A.left,B) || isSubStructure(A.right,B);
    }

//開始對比子樹
    public boolean treeCompare(TreeNode A, TreeNode B){
        // 第一次是不會進來,因為上面調用條件是A,B同時不為null
        // 之后再進來的前提則是A,B root 相同入客,對比child
        if (B == null) return true;

        //如果B == null 且 A != null 說明B 沒結束但A結束了 則肯定為false
        if (A == null) return false;

        if (A.val == B.val){
            return treeCompare(A.left,B.left) && treeCompare(A.right,B.right);
        }
        else return false;    
    }
}

劍指offer 27 二叉樹的鏡像
時間復雜度O(N)
空間復雜度O(N)

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public TreeNode mirrorTree(TreeNode root) {
        if(root == null) return null;
        // 暫存左子樹
        TreeNode temp = root.left;
        // 遞歸
        root.left = mirrorTree(root.right);
        root.right = mirrorTree(temp);
        //當無子節(jié)點時管毙,返回節(jié)點本身
        return root;
    }
}

劍指offer 28 對稱的二叉樹
時間復雜度O(N)
空間復雜度O(N)

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public boolean isSymmetric(TreeNode root) {
        if(root == null) return true;
        return isEqual(mirrorTree(root.right),root.left);
        }

    public TreeNode mirrorTree(TreeNode root){
        if(root == null) return null;
        TreeNode temp = root.left;
        root.left = mirrorTree(root.right);
        root.right = mirrorTree(temp);
        return root;
    }

    public boolean isEqual(TreeNode A, TreeNode B){
        if(A == null && B == null) return true;
        if(A == null && B != null) return false;
        if(A != null && B == null) return false;
        if(A.val != B.val) return false;
        return isEqual(A.left,B.left) && isEqual(A.right,B.right);
    }
}

劍指offer 32 從上到下打印二叉樹

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public int[] levelOrder(TreeNode root) {
        if(root == null) return new int[0];
        // 注意:LinkedList,雙大寫
        Queue<TreeNode> queue = new LinkedList<>();
        List<Integer> list = new ArrayList<>();
        queue.add(root);

        //注意:isEmpty()
        while(!queue.isEmpty()){
           TreeNode node = queue.poll();
           list.add(node.val);
           if(node.left != null) queue.add(node.left);
           if(node.right != null) queue.add(node.right);
        }
        int[] ans = new int[list.size()];
        // 括號之間用“;”隔開
        for(int i = 0; i<list.size(); i++){
            ans[i] = list.get(i);
        }

        return ans;
    }
}

劍指offer 32-ii 從上到下打印二叉樹 ii

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        Queue<TreeNode> queue = new LinkedList<>();
        List<List<Integer>> ans = new ArrayList<>();
        // 當root為null是,List也為null

        if(root != null) queue.add(root);
        while(!queue.isEmpty()){
            List<Integer> temp = new ArrayList<>();

            //注意:此時應從queue的size開始遞減,size為0時桌硫,queue為空
            for(int i = queue.size(); i > 0; i--){
                TreeNode node = queue.poll();
                temp.add(node.val);
                if(node.left != null) queue.add(node.left);
                if(node.right != null) queue.add(node.right);
            }

            ans.add(temp);
        }

        return ans;
    }
}

劍指offer 32-iii 從上到下打印二叉樹 iii
基本思路: queue的存儲順序不變夭咬,根據(jù)奇偶行,在組temp時進行前插或順序排列铆隘,進而達到改變偶行讀取順序

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        Queue<TreeNode> queue = new LinkedList<>();
        List<List<Integer>> ans = new ArrayList<>();
        int level = 1;

        if(root != null) queue.add(root);
        while(!queue.isEmpty()){
            LinkedList<Integer> temp = new LinkedList<>();
            int rem = level % 2;

            if(rem == 0){
                for(int i = queue.size(); i>0; i--){
                    TreeNode node = queue.poll();
                    // 偶行 從右至左
                    temp.addFirst(node.val);
                    if(node.left != null) queue.add(node.left);
                    if(node.right != null) queue.add(node.right);  
                }
            }
            else{
                for(int i = queue.size(); i>0; i--){
                    TreeNode node = queue.poll();
                    temp.add(node.val);
                    if(node.left != null) queue.add(node.left);
                    if(node.right != null) queue.add(node.right);
                }
            }
            ans.add(temp);
            level++;
        }
        return ans;
    }
}

劍指offer 33 二叉搜索樹的后序遍歷序列
基本思路:1.數(shù)列中最后一位是root
?????2.從左至右找出第一個比root大的node卓舵,位置記作temp(之后為右子樹,之前為左子樹)
?????3. temp之后若出現(xiàn)小于root膀钠,則為false

class Solution {
    public boolean verifyPostorder(int[] postorder) {
        // 數(shù)組 length不需要括號
        return orderCheck(postorder, 0, postorder.length-1);
    }

    public boolean orderCheck(int[] postorder, int left, int right){
        // 需要先判斷l(xiāng)eft 和 right 大小關系掏湾,否則會超出范圍
        if(left >= right) return true;
        int root = postorder[right];
        int firstLarge = left;

        // 找第一個大于root的節(jié)點
        while(postorder[firstLarge] < root){
            firstLarge++;
        }

        // 判斷之后是否都大于root
        for(int temp = firstLarge; temp < right; temp++){
            if(postorder[temp] < root) return false;
        }
        
        return orderCheck(postorder, left, firstLarge-1) && orderCheck(postorder, firstLarge, right-1);
        
    }
}

劍指offer 34 二叉樹中和為某一值的路徑
經典回溯問題

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    // 必須寫在外面,否則方法內不能調用
    public List<List<Integer>> ans = new ArrayList<>();
    public LinkedList<Integer> list = new LinkedList<>();

    public List<List<Integer>> pathSum(TreeNode root, int sum) {
        helper(root,sum);
        return ans;
    }

    //返回類型是void 空型 這里面如果return語句返回一個值的話會報錯肿嘲,
    //如果就只是一個return;表示程序結束不繼續(xù)往下執(zhí)行融击。
    public void helper(TreeNode root, int sum){
        if(root == null) return;
        sum -= root.val;
        list.add(root.val);

        if(root.left == null && root.right == null && sum == 0){
            // 值得注意的是,記錄路徑時若直接執(zhí)行 ans.add(list) 則是將 list 對象加入了 ans 雳窟;
            //后續(xù) list 改變時 ans 中的 list 對象也會隨之改變尊浪。
            //正確做法:ans.add(new ArrayList(list)) 相當于復制了一個 list 并加入到 ans
            ans.add(new ArrayList<>(list));
            // 這里不加remove和return的目的是,接下來的子node都是null封救,下一步自動return

        }
        helper(root.left,sum);
        helper(root.right,sum);
        // remove目的是不改變 public list
        list.removeLast();
    }
}

劍指offer 55i 二叉樹的深度
第一個完全一次作對的題目 :) 加油拇涤,別放棄

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public int maxDepth(TreeNode root) {
        if(root == null) return 0;
        return 1 + Math.max(maxDepth(root.left),maxDepth(root.right));
    }
}

劍指offer 55ii 平衡二叉樹

當左右平衡但子樹不平衡時

討論思考:如上圖所示,該題不僅要思考總樹是否平衡誉结,也要考慮子樹是否平衡鹅士。
不可以理所當然認為getDeepth由于迭代,會在node 2時返回 -1惩坑,從而省去
if(rightDeepth == -1 || leftDeepth == -1) return -1;
事實上掉盅,在node 2時,確實會返回-1以舒,但此時函數(shù)并未完成怔接,即并未回歸到node 1,故getDeepth(root)時,會返回Math.max(2,2)而非Math.max(3,3),所以最后仍不會得出正確答案稀轨。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public boolean isBalanced(TreeNode root) {
        if(root == null) return true;
        if(getDeepth(root) == -1) return false;
        return true;
    }
    public int getDeepth(TreeNode root){
        if(root == null) return 0;
        int leftDeepth = getDeepth(root.left);
        int rightDeepth = getDeepth(root.right);
        // 計算root的左右兩邊是否高度差是否大于1
        if(Math.abs(leftDeepth - rightDeepth) > 1) return -1;
        // 計算 左右子樹 的高度差是否大于1
        if(rightDeepth == -1 || leftDeepth == -1) return -1;
        
        return Math.max(leftDeepth,rightDeepth) + 1;
    }
}

劍指offer 37 序列化二叉樹
第一次挑戰(zhàn)困難的題,能夠讀懂并且寫明了岸军。 又進了一步奋刽,加油 :)

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Codec {
    TreeNode node;
    // Encodes a tree to a single string.
    // 雖然可以直接拼接字符串瓦侮,但是,在循環(huán)中佣谐,每次循環(huán)都會創(chuàng)建新的字符串對象肚吏,
    //然后扔掉舊的字符串。這樣狭魂,絕大部分字符串都是臨時對象罚攀,不但浪費內存,還會影響GC效率雌澄。
    public String serialize(TreeNode root) {
        if(root == null) return "null";
        Queue<TreeNode> queue = new LinkedList<>();
        StringBuilder sb = new StringBuilder();
        queue.add(root);
        while(!queue.isEmpty()){
            TreeNode node = queue.poll();
            // 1. 勿忘"null,"逗號  2. continue的作用:避免null上加null
            if(node == null) {
                sb.append("null,");
                continue;
                }
            sb.append(node.val + ",");
            queue.add(node.left);
            queue.add(node.right);
        }
        // 一定要toString();因為return的type是string
        return sb.toString();
    }

    // Decodes your encoded data to tree.
    public TreeNode deserialize(String data) {
        if(data == "null") return null;
        String[] str = data.split(",");
        Queue<TreeNode> queue = new LinkedList<>();
        TreeNode root = new TreeNode(Integer.parseInt(str[0]));
        queue.add(root);
        for(int i = 1;i < str.length; i++){
            /*
                1
               / \
              2   3
                 / \
                4   5
            當node 2沒有child時斋泄,會被從queue中拿出然后 i += 1; 進行下一個node
                */
            TreeNode parent = queue.poll();
            if(!"null".equals(str[i])){
                TreeNode left = new TreeNode(Integer.parseInt(str[i]));
                parent.left = left;
                queue.add(left);
            }
            i += 1;
            if(!"null".equals(str[i])){
                TreeNode right = new TreeNode(Integer.parseInt(str[i]));
                parent.right = right;
                queue.add(right);
            }
        }
        return root;
    }
}

// Your Codec object will be instantiated and called as such:
// Codec codec = new Codec();
// codec.deserialize(codec.serialize(root));

劍指offer 54 二叉搜索書的第k大節(jié)點

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    private int k;
    private int ans;
    public int kthLargest(TreeNode root, int k) {
        if(root == null) return 0;
        this.k = k;
        traversal(root);
        return ans;
    }
    // 右 根 左
    public void traversal(TreeNode root){
        if(root == null) return;
        traversal(root.right);
        
        if(--this.k == 0)  this.ans = root.val;
        traversal(root.left);
    }
}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市镐牺,隨后出現(xiàn)的幾起案子炫掐,更是在濱河造成了極大的恐慌,老刑警劉巖睬涧,帶你破解...
    沈念sama閱讀 211,123評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件募胃,死亡現(xiàn)場離奇詭異,居然都是意外死亡畦浓,警方通過查閱死者的電腦和手機痹束,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評論 2 384
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來讶请,“玉大人祷嘶,你說我怎么就攤上這事』嗝罚” “怎么了抹蚀?”我有些...
    開封第一講書人閱讀 156,723評論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長企垦。 經常有香客問我环壤,道長,這世上最難降的妖魔是什么钞诡? 我笑而不...
    開封第一講書人閱讀 56,357評論 1 283
  • 正文 為了忘掉前任郑现,我火速辦了婚禮,結果婚禮上荧降,老公的妹妹穿的比我還像新娘接箫。我一直安慰自己,他們只是感情好朵诫,可當我...
    茶點故事閱讀 65,412評論 5 384
  • 文/花漫 我一把揭開白布辛友。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪废累。 梳的紋絲不亂的頭發(fā)上邓梅,一...
    開封第一講書人閱讀 49,760評論 1 289
  • 那天,我揣著相機與錄音邑滨,去河邊找鬼日缨。 笑死,一個胖子當著我的面吹牛掖看,可吹牛的內容都是我干的匣距。 我是一名探鬼主播,決...
    沈念sama閱讀 38,904評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼哎壳,長吁一口氣:“原來是場噩夢啊……” “哼毅待!你這毒婦竟也來了?” 一聲冷哼從身側響起耳峦,我...
    開封第一講書人閱讀 37,672評論 0 266
  • 序言:老撾萬榮一對情侶失蹤恩静,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后蹲坷,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體驶乾,經...
    沈念sama閱讀 44,118評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,456評論 2 325
  • 正文 我和宋清朗相戀三年循签,在試婚紗的時候發(fā)現(xiàn)自己被綠了级乐。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,599評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡县匠,死狀恐怖风科,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情乞旦,我是刑警寧澤贼穆,帶...
    沈念sama閱讀 34,264評論 4 328
  • 正文 年R本政府宣布,位于F島的核電站兰粉,受9級特大地震影響故痊,放射性物質發(fā)生泄漏。R本人自食惡果不足惜玖姑,卻給世界環(huán)境...
    茶點故事閱讀 39,857評論 3 312
  • 文/蒙蒙 一愕秫、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧焰络,春花似錦戴甩、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春缴川,著一層夾襖步出監(jiān)牢的瞬間囱稽,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評論 1 264
  • 我被黑心中介騙來泰國打工二跋, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人流昏。 一個月前我還...
    沈念sama閱讀 46,286評論 2 360
  • 正文 我出身青樓扎即,卻偏偏與公主長得像,于是被迫代替她去往敵國和親况凉。 傳聞我的和親對象是個殘疾皇子谚鄙,可洞房花燭夜當晚...
    茶點故事閱讀 43,465評論 2 348

推薦閱讀更多精彩內容