力扣【二叉树】相关题目

二叉树

二叉树最基本的思想就是 递归,如果要求不让用 递归,那就用 bfs 求解。

226. 反转二叉树

void dfs(TreeNode* &u)
{
    if (!u) return;
    dfs(u -> left);
    dfs(u -> right);
    swap(u -> left, u -> right);
}

TreeNode* invertTree(TreeNode* root) {
    dfs(root);
    return root;
}

101. 判断对称二叉树

二叉树的问题关键在于找到可以递归的点,也就是有个功能A想要实现,但实现又要用功能A实现后的功能。

如何判断是否为对称二叉树?

如果 root 为空则对称,否则左右子树对称则对称。

如何判断左右子树对称?

左子树的左孩子的子树和右子树的右孩子的子树对称且左子树的右孩子的子树和右子树的左孩子的子树对称。

bool compare(TreeNode* u1, TreeNode* u2)
{
    if (u1 == nullptr && u2 != nullptr) return false;
    else if (u1 != nullptr && u2 == nullptr) return false;
    else if (u1 == nullptr && u2 == nullptr) return true;
    else if (u1 -> val != u2 -> val) return false;

    return compare(u1 -> left, u2 -> right) && compare(u1 -> right, u2 -> left);       
}

bool isSymmetric(TreeNode* root) {
    if (root == nullptr) return true;
    return compare(root -> left, root -> right);
}

110. 判断平衡二叉树

如何求每个结点的高度
bool flag = true;

int dfs(TreeNode* u)
{
    if (u == nullptr) return 0;
    int lefth = dfs(u -> left);
    int righth = dfs(u -> right);
    if (abs(lefth - righth) > 1) flag = false;
    return max(lefth, righth) + 1;
}

bool isBalanced(TreeNode* root) {
    dfs(root);
    return flag;
}

105 106. 中序和前序(后序)构造二叉树

unordered_map<int, int> mp;

TreeNode * getTree(int pl, int pr, int ml, int mr, vector<int> pre)
{
    if (pl > pr) return nullptr;
    int val = pre[pl];
    TreeNode * node = new TreeNode(val);

    int k = mp[val], len = k - 1 - ml;
    node -> left = getTree(pl + 1, pl + 1 + len, ml, k - 1, pre);
    node -> right = getTree(pl + 2 + len, pr, k + 1, mr, pre);
    return node;
}

TreeNode* buildTree(vector<int>& pre, vector<int>& mid) {
    int n = pre.size();
    for (int i = 0; i < n; i ++ ) mp[mid[i]] = i;

    TreeNode * root = getTree(0, n - 1, 0, n - 1, pre);
    return root;
}

617. 合并二叉树

TreeNode * getTree(TreeNode * u1, TreeNode * u2)
{
    if (!u1 && !u2) return nullptr;
    TreeNode * node = new TreeNode();

    if (u2) swap(u1, u2);

    if (u2) node -> val = u1 -> val + u2 -> val;
    else node -> val = u1 -> val;

    node -> left = getTree(u1 -> left, u2 ? u2 -> left : nullptr);
    node -> right = getTree(u1 -> right, u2 ? u2 -> right : nullptr);

    return node;
}

TreeNode* mergeTrees(TreeNode* root1, TreeNode* root2) {
    TreeNode * root = getTree(root1, root2);
    return root;
}

98. 验证二叉搜索树

定义法

如何判断左子树的所有值都小于该点的值,右子树所有值都大于该点的值?

通过维护左右子树各自的 max min 来判断。

如何维护左右子树各自的 max min
vector<int> dfs(TreeNode* u)
{
    vector<int> res({1, u -> val, u -> val});
    if (u -> left)
    {
        auto t = dfs(u -> left);
        if (!t[0] || t[2] >= u -> val) res[0] = 0;
        res[1] = min(res[1], t[1]);
        res[2] = max(res[2], t[2]);
    }
    if (u -> right)
    {
        auto t = dfs(u -> right);
        if (!t[0] || t[1] <= u -> val) res[0] = 0;
        res[1] = min(res[1], t[1]);
        res[2] = max(res[2], t[2]);
    }
    return res;
}

bool isValidBST(TreeNode* root) {
    if (!root) return true;
    return dfs(root)[0];
}
中序遍历

利用二叉排序树的性质,其中序遍历的结果一定是单调增的序列。


530. 二叉搜索树的最小绝对差

遇到在二叉搜索树上求最值,求差值的问题,就想成在一个有序数组上求最值和差值的问题

也就是说,中序遍历二叉排序树相当于递增顺序遍历一个数组

最小差只可能在相邻的两个数之间。

int res = 0x3f3f3f3f, pre = 0x3f3f3f3f;

void dfs(TreeNode* u)
{
    if (u == nullptr) return;
    dfs(u -> left);
    res = min(res, abs(u -> val - pre));
    pre = u -> val;
    dfs(u -> right);
}

int getMinimumDifference(TreeNode* root) {
    dfs(root);
    return res;
}

501. 二叉树中的众数 vs. 二叉搜索树中的众数

普通二叉树中的众数
unordered_map<int, int> mp;

void dfs(TreeNode* root)
{
    if (!root) return;
    mp[root -> val] ++;
    dfs(root -> left);
    dfs(root -> right);
}

static bool cmp(pair<int, int> &a, pair<int, int> &b)
{
    return a.second > b.second;
}

vector<int> findMode(TreeNode* root) {
    dfs(root);
    vector<pair<int, int>> res(mp.begin(), mp.end());
    sort(res.begin(), res.end(), cmp);

    int maxv = res[0].second;
    vector<int> ans;
    for (auto t : res)
        if (t.second == maxv) ans.push_back(t.first);
        else break;
    return ans;
}
二叉搜索树中的众数:不使用额外空间
vector<int> ans;
int maxc = 0, curc = 0, last = -1e5 - 1;

void dfs(TreeNode* u)
{
    if (!u) return;
    dfs(u -> left);

    if (last == -1e5 - 1 || u -> val == last) curc ++, 
	else curc = 1;
    last = u -> val;
    
    if (curc > maxc) ans = {u -> val}, maxc = curc;
    else if (curc == maxc) ans.push_back({u -> val});

    dfs(u -> right);
}

vector<int> findMode(TreeNode* root) {
    dfs(root);
    return ans;
}

236. 二叉树的最近公共祖先

最近公共祖先就是第一个左子树包含 p或q 右子树包含 q或p 的节点。

用二进制返回值表示有无 pq00 表示无p无q10表示有q无p,同理类推。

// O(n)
TreeNode* res = NULL;

int dfs(TreeNode * u, TreeNode* p, TreeNode* q)
{
    if (!u) return 0;
    int state = 0;
    state |= dfs(u -> left, p, q);
    state |= dfs(u -> right, p, q);
    if (u == p) state |= 1;
    else if (u == q) state |= 2;
    if (state == 3 && !res) res = u;
    return state;
}

TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
    dfs(root, p, q);
    return res;
}

235. 二叉搜索树的最近公共祖先

// O(h)
TreeNode* res = NULL;

void dfs(TreeNode* u, TreeNode* p, TreeNode* q)
{
    if (u == NULL) return;
    if ((p -> val <= u -> val && q -> val >= u -> val) || 
        (p -> val >= u -> val && q -> val <= u -> val))
    {
        res = u;
        return;
    }
    if (p -> val > u -> val) dfs(u -> right, p, q);
    if (p -> val < u -> val) dfs(u -> left, p, q);
}

TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
    dfs(root, p, q);
    return res;
}

701. 二叉搜索树中插入一个节点

TreeNode* insertIntoBST(TreeNode* root, int val) {
    if (!root) return new TreeNode(val);
    if (root -> val > val) root -> left = insertIntoBST(root -> left, val);
    if (root -> val < val) root -> right = insertIntoBST(root -> right, val);
    return root;
}

450. 在二叉搜索树中删除一个节点

当删除节点的时候一共会有几种情况,核心思想就是保证中序遍历永远是升序的就行:

在这里插入图片描述

TreeNode* deleteNode(TreeNode* root, int key) {
    del(root, key);
    return root;
}

void del(TreeNode* &u, int key)
{
    if (!u) return;
    if (u -> val == key)
    {
        if (!u -> right && ! u -> left) u = nullptr;
        else if (!u -> left) u = u -> right;
        else if (!u -> right) u = u -> left;
        else
        {
            auto p = u -> right;
            while (p -> left) p = p -> left;
            u -> val = p -> val;
            del(u -> right, p -> val);
        }
    } 
    else if (u -> val > key) del(u -> left, key);
    else del(u -> right, key);
}

669. 修剪二叉搜索树

如果当前节点小于 low 那么整个左子树都要被修掉,因此递归右子树,返回符合条件的头结点。

同理,当前节点大于 high 那么整个右子树都要被修掉,因此递归左子树,返回符合条件的头结点。

如果当前节点在区间之间,那么左右子树分别修剪。

TreeNode* trimBST(TreeNode* root, int low, int high) {
    if (!root) return nullptr;
    if (root -> val < low) return trimBST(root -> right, low, high);
    if (root -> val > high) return trimBST(root -> left, low, high);
    root -> left = trimBST(root -> left, low, high);
    root -> right = trimBST(root -> right, low, high);
    return root; 
}

108. 构造平衡二叉树

TreeNode* getval(vector<int> nums, int l, int r)
{
    if (l > r) return nullptr;
    int mid = (l + r) / 2;
    TreeNode* node = new TreeNode(nums[mid]);
    node -> left = getval(nums, l, mid - 1);
    node -> right = getval(nums, mid + 1, r);
    return node;
}

TreeNode* sortedArrayToBST(vector<int>& nums) {
    TreeNode* root = getval(nums, 0, nums.size() - 1);
    return root;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值