成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

我們一起聊聊十五周算法—二叉搜索樹(BST)

開發 前端
BST有一個重要的性質:BST的中序遍歷結果是有序的(升序),也就是在中序位置可以將每個節點的值升序打印出來。

今天是十五周算法訓練營的第五周,主要講二叉搜索樹專題,包含:驗證二叉搜索樹、不同的二叉搜索樹、二叉樹的最近公共祖先、二叉搜索樹的最近公共祖先。(歡迎加入十五周算法訓練營,與小伙伴一起卷算法)

BST的特性:

對于BST的每一個節點node,左子樹節點的值都比node的值要小,右子樹節點的值都比node的值大;

對于BST的每一個節點node,它的左側子樹和右側子樹都是BST。

BST有一個重要的性質:BST的中序遍歷結果是有序的(升序),也就是在中序位置可以將每個節點的值升序打印出來

void traverse(TreeNode root) {
     if (root == null) return;
     traverse(root.left);
     // 中序遍歷代碼位置
     print(root.val);
     traverse(root.right);
}

驗證二叉搜索樹

給你一個二叉樹的根節點 root ,判斷其是否是一個有效的二叉搜索樹。

有效 二叉搜索樹定義如下:

節點的左子樹只包含 小于 當前節點的數。 節點的右子樹只包含 大于 當前節點的數。 所有左子樹和右子樹自身必須也是二叉搜索樹。

示例 1:

輸入:root = [2,1,3] 輸出:true

根據二叉搜索樹特性,通過中序遍歷獲取。

// 解題思路:
// 1. 是否可以通過遍歷一遍二叉樹得到答案?
// 通過中序遍歷可以得到,因為BST的中序遍歷是一個升序結果
function isValidBST1(root) {
    let inorder = -Infinity;
    let result = true;
    let traverse = root => {
        if (root === null) {
            return;
        }

        // 前序位置
        traverse(root.left);
        // 中序位置
        // 中序位置獲取當前值,并比較其和前一個值的大小,如果小于等于前一個值,則證明不是BST樹,則將結果變為false
        if (root.val <= inorder) {
            result = false;
        } else {
            inorder = root.val;
        }
        traverse(root.right);
        // 后續位置
    };

    traverse(root);

    return result;
}

// 將中序遍歷變為循環的方式
function isValidBST2(root) {
    if (root === null) {
        return true;
    }
    let head = root;
    const stack = [];
    let inorder = -Infinity;

    // 中序遍歷的循環結構是需要創建一個棧,然后先將左節點全壓入棧中
    while (stack.length > 0 || head !== null) {
        // 當head不為空時,壓入棧中
        if (head !== null) {
            stack.push(head);
            head = head.left;
        } else {
            // 彈出棧頂元素
            head = stack.pop();
            if (inorder >= head.val) {
                return false;
            }
            inorder = head.val;
            head = head.right;
        }
    }

    return true;
}

// 2. 是否可以定義一個遞歸函數,通過子問題(子樹)的答案推導出原問題的答案?
// 答案是可以的,因為搜索二叉樹的性質是:
// (1)對于BST的每一個節點node,左子樹節點值都比node的值要小,右子樹節點的值逗比node的值大;
// (2)對于BST的每一個節點node,它的左側子樹和右側子樹都是BST
// 則我們解決該問題可定義一個遞歸函數來進行解決

// 注意:該問題需要借助外部變量,因為根節點的值必須大于左子樹所有值、小于右子樹所有值,所以需要引入最大最小值

function isValidBST3(root) {
    // 構造一個輔助函數,判斷根節點是否在(min,max)范圍內
    const helper = (root, min, max) => {
        if (root === null) {
            return true;
        }

        if (root.val <= min) {
            return false;
        }

        if (root.val >= max) {
            return false;
        }

        return helper(root.left, min, root.val) && helper(root.right, root.val, max);
    };

    // 初始狀態min為-Infinity,max為Infinity
    return helper(root, -Infinity, Infinity);
}

不同的二叉搜索樹

給你一個整數 n ,求恰由 n 個節點組成且節點值從 1 到 n 互不相同的 「二叉搜索樹」 有多少種?返回滿足題意的二叉搜索樹的種數。

示例 1:」

圖片

輸入:n = 3

輸出:5

利用的也是左子樹值 < 根節點 < 右子樹值

// 對于BST的每一個節點node,左子樹節點的值都比node的值要小,右子樹節點的值都比node的值大

// 在該問題中,1~n都有可能成為根節點,然后左邊的是左子樹上的點,右邊的是右子樹上的點,然后對應根節點的搜索樹數量就是左子樹的組合數 * 右子樹的組合數;

// 該問題明顯就轉換為一個遞歸問題

function numTree(n) {
    // 為了解決子問題的重復問題,需要引入備忘錄
    const memo = [];
    for (let i = 0; i < n + 1; i++) {
        memo.push([]);
        for (let j = 0; j < n + 1; j++) {
            memo[i].push(0);
        }
    }
    const count = (low, high) => {
        // 遞歸終止條件
        if (low > high) {
            return 1;
        }

        // 判斷備忘錄中是否存在該值,存在的話直接使用
        if (memo[low][high] > 0) {
            return memo[low][high];
        }
        let result = 0;

        for (let i = low; i <= high; i++) {
            const left = count(low, i - 1);
            const right = count(i + 1, high);

            result += left * right;
        }

        // 將結果存儲到備忘錄中
        memo[low][high] = result;

        return result;
    };

    return count(1, n);
}

console.log(numTree(3));

二叉樹的最近公共祖先

給定一個二叉樹, 找到該樹中兩個指定節點的最近公共祖先。

百度百科中最近公共祖先的定義為:“對于有根樹 T 的兩個節點 p、q,最近公共祖先表示為一個節點 x,滿足 x 是 p、q 的祖先且 x 的深度盡可能大(一個節點也可以是它自己的祖先)。”

示例 1:

圖片

輸入:root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1 輸出:3 解釋:節點 5 和節點 1 的最近公共祖先是節點 3 。

// 通過遞歸解決(后續遍歷)
function lowestCommonAncestor(root, p, q) {
    // 確定遞歸函數
    const traverse = (node, p, q) => {
        // 確定遞歸終止條件
        if (node === null || node === p || node === q) {
            return node;
        }

        const left = traverse(node.left, p, q);
        const right = traverse(node.right, p, q);

        // 后續位置
        // 找到一個節點,其發現p、q節點分別出現在其左右子樹上
        if (left !== null && right !== null) {
            return node;
        }

        // p或q本身就是最近公共祖先
        if (left === null) {
            return right;
        }

        return left;
    };

    return traverse(root, p, q);
}

二叉搜索樹的最近公共祖先

給定一個二叉搜索樹, 找到該樹中兩個指定節點的最近公共祖先。

百度百科中最近公共祖先的定義為:“對于有根樹 T 的兩個結點 p、q,最近公共祖先表示為一個結點 x,滿足 x 是 p、q 的祖先且 x 的深度盡可能大(一個節點也可以是它自己的祖先)。”

例如,給定如下二叉搜索樹:  root = [6,2,8,0,4,7,9,null,null,3,5]

示例 1:

圖片

輸入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 8 輸出: 6 解釋: 節點 2 和節點 8 的最近公共祖先是 6。

// 因為是二叉搜索樹,其是有順序的,所以找最近公共祖先節點的問題就轉換成了該節點在[p, q]中間即可
function lowestCommonAncestor(root, p, q) {
    const helper = (node, p, q) => {
        if (node === null) {
            return node;
        }

        if (node.val > p.val && node.val > q.val) {
            const left = helper(node.left, p, q);

            if (left !== null) {
                return left;
            }
        }

        if (node.val < p.val && node.val < q.val) {
            const right = helper(node.right, p, q);
            if (right !== null) {
                return right;
            }
        }

        return node;
    };

    return helper(root, p, q);
}

責任編輯:武曉燕 來源: 前端點線面
相關推薦

2023-05-08 07:32:03

BFSDFS路徑

2023-02-01 07:27:46

序列化二叉樹根節點

2023-06-19 07:31:34

普通動態規劃字符串

2021-09-02 11:31:28

二叉搜索樹迭代法公共祖先

2021-08-26 11:31:11

二叉樹數據結構算法

2023-10-10 08:00:07

2022-08-30 13:48:16

LinuxMySQL內存

2024-02-20 21:34:16

循環GolangGo

2021-08-27 07:06:10

IOJava抽象

2023-08-10 08:28:46

網絡編程通信

2023-08-04 08:20:56

DockerfileDocker工具

2023-06-30 08:18:51

敏捷開發模式

2022-05-24 08:21:16

數據安全API

2023-09-10 21:42:31

2022-10-28 07:27:17

Netty異步Future

2022-11-12 12:33:38

CSS預處理器Sass

2022-06-26 09:40:55

Django框架服務

2023-04-26 07:30:00

promptUI非結構化

2022-02-14 07:03:31

網站安全MFA

2025-03-27 02:00:00

SPIJava接口
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 日韩久久久久久 | 国产伦精品一区二区三区照片91 | 三级在线视频 | 欧美精品中文字幕久久二区 | 久久久久久国模大尺度人体 | 精品国产一级 | 在线区 | 日本在线综合 | 成人精品国产免费网站 | 香蕉一区二区 | 欧美日韩精品影院 | 日韩欧美国产一区二区 | 久久久精品一区二区三区 | 91免费高清视频 | 精品久久香蕉国产线看观看亚洲 | 男人天堂色 | 欧美美女一区二区 | 国产精品自在线 | 成人国产免费视频 | 亚洲国产一区视频 | 久久久久久91 | 国产欧美一区二区三区在线看 | 在线看亚洲 | 91偷拍精品一区二区三区 | 九九久久免费视频 | 国产中文字幕在线观看 | 一级片免费网站 | 黄色片a级 | 99re视频在线观看 | 国产精品成人一区二区 | 成人国产精品久久 | 超碰在线人人 | 国产成人叼嘿视频在线观看 | 亚洲视频在线一区 | 国产免费一区 | 日韩在线免费视频 | 精品国产乱码久久久久久牛牛 | 亚洲精品大片 | 久热久 | 国产不卡一区在线观看 | 视频精品一区二区三区 |