左神算法筆記——樹形DP問題

——總結(jié)左神進階班第四甜滨、五課有關樹的一些問題匯總
目錄:

  • 判斷一顆樹是否是平衡二叉樹
  • 尋找最大二叉搜索樹(節(jié)點個數(shù)和頭節(jié)點)
  • 尋找一個樹中最大值和最小值(節(jié)點和值)
  • 求一顆二叉樹上面的最遠距離
  • 員工活躍度問題

判斷一顆樹是否是平衡二叉樹

LeetCode | 面試題55 - II. 平衡二叉樹

基本思路:

  • 首先獲取所需信息:

    • 當前樹的左子樹是否是平衡二叉樹
    • 當前樹的右子樹是否是平衡二叉樹
    • 當前樹的左子樹的高度
    • 當前樹的右子樹的高度
  • 整合所用信息

    • 如果左右子樹有一個不是平衡二叉樹,那么當前的樹肯定也不是平衡二叉樹如蚜。
    • 如果左右子樹都是平衡二叉樹恐锣,且左右子樹的高度差不超過1夹囚,那么是平衡樹隙咸,否則不是平衡二叉樹沐悦。

代碼如下:

    static class TreeNode {
        int val;
        TreeNode left;
        TreeNode right;

        public TreeNode(int val) {
            this.val = val;
        }
    }

    // 創(chuàng)建對象信息集
    static class State{
        boolean isAvl;   // 當前樹是否是平衡二叉樹
        int h;           // 當前樹的高度

        // 構(gòu)造器
        public State(boolean isAvl, int h) {
            this.isAvl = isAvl;
            this.h = h;
        }
    }

    // 判斷一顆樹是否是平衡二叉樹
    public static boolean isAvl(TreeNode root){
        return getAns(root).isAvl;
    }

    private static State getAns(TreeNode root) {
        if(root == null) return new State(true,0);
        // 獲取左右子樹的各自信息
        State l = getAns(root.left);
        State r = getAns(root.right);
        // case——true;
        if(!l.isAvl || !r.isAvl || Math.abs(l.h - r.h) > 1){
            return new State(false,0);
        }
        // case——false
        return new State(true,Math.max(l.h,r.h) + 1);
    }


尋找最大二叉搜索樹(節(jié)點個數(shù)和頭節(jié)點)

LintCode910 | 尋找最大二叉搜索子樹 —— 需要會員
題目描述:

給定一顆二叉樹的頭節(jié)點head,請返回最大搜索二叉子樹的大小五督。

基本思路:

  • 首先搜索所用信息:
    • 左、右子樹中最大搜索二叉樹的頭節(jié)點瓶殃。
    • 左充包、右子樹中最大二叉搜索子樹的節(jié)點個數(shù)。
    • 左遥椿、右子樹中的最小節(jié)點值
    • 左基矮、右子樹中的最大節(jié)點值
  • 進行所用信息的整合
    • case1 : 如果當前左右兩顆樹可以整合為一顆二叉搜索樹。
    • case2 : 如果當前左右子樹無法整為一顆二叉搜索樹冠场,從左右子樹中挑選一顆較大搜索二叉樹家浇。

代碼如下:

    static class TreeNode {
        int val;
        TreeNode left;
        TreeNode right;

        public TreeNode(int val) {
            this.val = val;
        }
    }

    // 創(chuàng)建對象信息集
    static class State{
        TreeNode head;
        int size;
        int min;
        int max;

        public State(TreeNode head, int size, int min, int max) {
            this.head = head;
            this.size = size;
            this.min = min;
            this.max = max;
        }
    }

    // 返回最大的二叉搜索子樹的頭節(jié)點
    public static TreeNode getMaxBST(TreeNode root){
        return getAns(root).head;
    }

    private static State getAns(TreeNode root) {
        if(root == null) return new State(null,0,Integer.MAX_VALUE,Integer.MIN_VALUE);
        // 獲取左右子樹的信息
        State l = getAns(root.left);
        State r = getAns(root.right);

        // case1: 左右子樹可以整合成一顆二叉搜索樹
        int union = 0;
        if(l.head == root.left && r.head == root.right && root.val > l.max && root.val < r .min){
            union = l.size + r.size + 1;
        }
        // case2、3
        int p1 = l.size;
        int p2 = r.size;
        int maxSize = Math.max(Math.max(p1,p2),union);
        TreeNode maxHead = p1 > p2 ? l.head : r.head;
        if(maxSize == union){
            maxHead = root;
        }
        return new State(maxHead,maxSize,
                Math.min(Math.min(l.min,r.min),root.val),Math.max(Math.max(l.max,r.max),root.val));
    }


尋找一個樹中最大值和最小值(節(jié)點和值)

基本思路:

  • 首先進行信息獲取
    • 需要左子樹和右子樹各自的最小值
    • 左子樹和右子樹各自的最大值
  • 整合信息碴裙;
    • 小值為左子樹的最小值钢悲、右子樹的最小值,以及當前root的值的最小值舔株。
    • 樹的最大值為左子樹的最大值莺琳、右子樹的最大值,以及當前root的值的最大值载慈。

代碼如下:

    // 創(chuàng)建對象信息集
    static class State{
        int min;
        int max;

        public State(int min, int max) {
            this.min = min;
            this.max = max;
        }
    }

    // 返回二叉樹中的最大值和最小值
    public static int[] getTreeBorderValue(TreeNode root){
        State res = getAns(root);
        return new int[]{res.min,res.max};
    }

    private static State getAns(TreeNode root) {
        if(root == null) return new State(Integer.MAX_VALUE, Integer.MIN_VALUE);
        // 獲取左右子樹的信息
        State l = getAns(root.left);
        State r = getAns(root.right);
        // 整合信息
        return new State(Math.min(Math.max(l.min,r.min),root.val),Math.max(Math.max(l.max,r.max),root.val));
    }

    public static void main(String[] args) {
        TreeNode head1 = new TreeNode(1);
        head1.left = new TreeNode(2);
        head1.right = new TreeNode(3);
        head1.left.left = new TreeNode(4);
        head1.left.right = new TreeNode(5);
        head1.right.left = new TreeNode(6);
        head1.right.right = new TreeNode(7);
        head1.left.left.left = new TreeNode(8);
        head1.right.left.right = new TreeNode(9);
        int[] arr1 = getTreeBorderValue(head1);
        System.out.println(Arrays.toString(arr1));

        TreeNode head2 = new TreeNode(1);
        head2.left = new TreeNode(2);
        head2.right = new TreeNode(3);
        head2.right.left = new TreeNode(4);
        head2.right.right = new TreeNode(5);
        head2.right.left.left = new TreeNode(6);
        head2.right.right.right = new TreeNode(7);
        head2.right.left.left.left = new TreeNode(8);
        head2.right.right.right.right = new TreeNode(9);
        int[] arr2 = getTreeBorderValue(head2);
        System.out.println(Arrays.toString(arr2));
    }


求一顆二叉樹上面的最遠距離

題目描述:

在二叉樹中惭等,一個節(jié)點可以往上走也可以往下走,那么節(jié)點A總能走到節(jié)點B办铡。
節(jié)點A走到節(jié)點B的距離為:A走到B最短路徑上的節(jié)點個數(shù)辞做。
求一顆二叉樹上的最遠距離。

基本思路:

  • 首先獲取有用的信息:
    • 左右子樹上的最遠距離
    • 左右子樹各自的高度
  • 整合相關的有用信息:
    • 當前樹中的最長距離為左子樹的最長距離寡具,右子樹的最長距離以及當前左子樹高度加上右子樹高度加1中取最大秤茅。

代碼如下:

    static class TreeNode {
        int val;
        TreeNode left;
        TreeNode right;

        public TreeNode(int val) {
            this.val = val;
        }
    }

    // 創(chuàng)建對象信息集
    static class State{
        int maxLen;   // 當前樹的最大距離
        int height;   // 當前樹的高度

        State(int maxLen, int height) {
            this.maxLen = maxLen;
            this.height = height;
        }
    }

    // 返回二叉樹中的最大值和最小值
    public static int getMaxLength(TreeNode root){
        return getAns(root).maxLen;
    }

    private static State getAns(TreeNode root) {
        if(root == null) return new State(0, 0);
        // 獲取左右子樹的信息
        State l = getAns(root.left);
        State r = getAns(root.right);
        // 整合信息
        return new State(Math.max(Math.max(l.maxLen,r.maxLen),(l.height + r.height + 1)),
                Math.max(l.height,r.height) + 1);
    }

員工活躍度問題

問題描述:

員工活躍度

基本思路:

  • 對于任何一個員工,都有兩種可能性晒杈。情況一是該員工來的活躍度嫂伞,情況二是該員工不來的活躍度。
  • 那么結(jié)果只需要返回root員工,也就是大boos(上級是他自己)的來和不來兩種情況下最大活躍度
  • 如果大boss來帖努, 那么當前結(jié)果為boss的活躍度 加上所有boos直系子員工不來的活躍度撰豺。
  • 如果大boss不來,那么當前結(jié)果就是boss直系子員工來或不來活躍度的自大值拼余。
  • 最終比較來或者不來的活躍度污桦,取最大值。

如果給出的matirx是以樹結(jié)構(gòu)呈現(xiàn),則代碼如下:

    static class Node {
        int huo;              // 員工活躍度
        List<Node> subNodes;  // 下屬員工活躍度集合

        public Node(int huo){
            this.huo = huo;
            subNodes = new LinkedList<>();
        }
    }

    // 創(chuàng)建對象信息集
    static class State{
        int lai_huo;      // 當前員工來的活躍度
        int bu_lai_huo;   // 當前員工不來的活躍度

        public State(int lai_huo, int bu_lai_huo) {
            this.lai_huo = lai_huo;
            this.bu_lai_huo = bu_lai_huo;
        }
    }

    // 返回二叉樹中的最大值和最小值
    public static int getMaxHappy(Node root){
        State boss = getAns(root);
        return Math.max(boss.bu_lai_huo,boss.lai_huo);
    }
    
    private static State getAns(Node root) {
        int lai_huo = root.huo;
        int bu_lai_hup = 0;

        for (int i = 0; i < root.subNodes.size(); i++) {
            Node empty = root.subNodes.get(i);
            State cur = getAns(empty);
            lai_huo += cur.bu_lai_huo;
            bu_lai_hup += Math.max(cur.lai_huo,cur.bu_lai_huo);
        }
        
        return new State(lai_huo,bu_lai_hup);
    }

如果給出的是二維數(shù)組的結(jié)構(gòu)匙监,則用動態(tài)規(guī)劃的思想取求解凡橱,代碼如下:


    // 獲取最大的活躍值
    public static int getMaxHappy(int[][] matrix){
        // 創(chuàng)建一個二維數(shù)組存儲活躍度信息
        int[][] dp = new int[matrix.length][2];
        // 第一個元素表示該員工來的活躍度,第二個元素表示員工不來的活躍度
        boolean[] visited = new boolean[matrix.length];  // 創(chuàng)建數(shù)組亭姥,表示當前員工是否已經(jīng)訪問過
        // 遍歷martix稼钩,找出大boss的位置
        int boss = 0;
        for (int i = 0; i < matrix.length; i++) {
            if(i == matrix[i][0]){
                boss = i;
                break;
            }
        }
        // 進入遞歸返回最大
        process(matrix,dp,visited,boss);
        return Math.max(dp[boss][0],dp[boss][1]);
    }

    private static void process(int[][] matrix, int[][] dp, boolean[] visited, int boss) {
        visited[boss] = true;       // 計算boss的信息
        dp[boss][0] = matrix[boss][1];  // 賦值活躍度
        for (int i = 0; i < matrix.length; i++) {
            if(matrix[i][0] == boss && !visited[boss]){
                process(matrix, dp, visited, i);
                dp[boss][0] += dp[i][1];
                dp[boss][1] += Math.max(dp[i][0],dp[i][1]);
            }
        }
    }
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市达罗,隨后出現(xiàn)的幾起案子坝撑,更是在濱河造成了極大的恐慌,老刑警劉巖粮揉,帶你破解...
    沈念sama閱讀 217,509評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件巡李,死亡現(xiàn)場離奇詭異,居然都是意外死亡扶认,警方通過查閱死者的電腦和手機侨拦,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評論 3 394
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來辐宾,“玉大人狱从,你說我怎么就攤上這事◇Ω牛” “怎么了矫夯?”我有些...
    開封第一講書人閱讀 163,875評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長吊洼。 經(jīng)常有香客問我训貌,道長,這世上最難降的妖魔是什么冒窍? 我笑而不...
    開封第一講書人閱讀 58,441評論 1 293
  • 正文 為了忘掉前任递沪,我火速辦了婚禮,結(jié)果婚禮上综液,老公的妹妹穿的比我還像新娘款慨。我一直安慰自己,他們只是感情好谬莹,可當我...
    茶點故事閱讀 67,488評論 6 392
  • 文/花漫 我一把揭開白布檩奠。 她就那樣靜靜地躺著桩了,像睡著了一般。 火紅的嫁衣襯著肌膚如雪埠戳。 梳的紋絲不亂的頭發(fā)上井誉,一...
    開封第一講書人閱讀 51,365評論 1 302
  • 那天,我揣著相機與錄音整胃,去河邊找鬼颗圣。 笑死,一個胖子當著我的面吹牛屁使,可吹牛的內(nèi)容都是我干的在岂。 我是一名探鬼主播,決...
    沈念sama閱讀 40,190評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼蛮寂,長吁一口氣:“原來是場噩夢啊……” “哼蔽午!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起酬蹋,我...
    開封第一講書人閱讀 39,062評論 0 276
  • 序言:老撾萬榮一對情侶失蹤祠丝,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后除嘹,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,500評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡岸蜗,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,706評論 3 335
  • 正文 我和宋清朗相戀三年尉咕,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片璃岳。...
    茶點故事閱讀 39,834評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡年缎,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出铃慷,到底是詐尸還是另有隱情单芜,我是刑警寧澤,帶...
    沈念sama閱讀 35,559評論 5 345
  • 正文 年R本政府宣布犁柜,位于F島的核電站洲鸠,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏馋缅。R本人自食惡果不足惜扒腕,卻給世界環(huán)境...
    茶點故事閱讀 41,167評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望萤悴。 院中可真熱鬧瘾腰,春花似錦、人聲如沸覆履。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,779評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至栖雾,卻和暖如春楞抡,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背岩灭。 一陣腳步聲響...
    開封第一講書人閱讀 32,912評論 1 269
  • 我被黑心中介騙來泰國打工拌倍, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人噪径。 一個月前我還...
    沈念sama閱讀 47,958評論 2 370
  • 正文 我出身青樓柱恤,卻偏偏與公主長得像,于是被迫代替她去往敵國和親找爱。 傳聞我的和親對象是個殘疾皇子梗顺,可洞房花燭夜當晚...
    茶點故事閱讀 44,779評論 2 354

推薦閱讀更多精彩內(nèi)容