算法与数据结构---二叉树相关问题

最优二叉树II

题目说明

在这里插入图片描述
在这里插入图片描述

思路

首先题目直接给我的两个关键点是:

1. 中序遍历
2. 总开销最小

关于第二点,基本上会选择想到说可能要用递归或者dp,来搜索到多个候选的结果,然后从中比较出最优的结果返回。
再说第一点,中序遍历的数组的话会可以重建出来很多的二叉树,最重要的是要选择出根节点,选出根节点后就可以分为左右子树,然后左右子树又可以继续选择根节点再分为子树。
左右子树的终止条件是,结点为空,可以用if(l>r) return 0 来表示。

代码(C++)

以下代码有详细的注释,参考了该牛客同学的题解,具体为:

#include <bits/stdc++.h>
#include <algorithm>
#include <iostream>
using namespace std;

// 先根据题意,分配足够大的数组,用做memo
const int N=301;
int w[N];
int f[N][N][N];
int n;


// brief: 求解在[l,r]范围内,以p为父节点时的最优二叉树的数值
//        在该过程中,需要遍历[l,r],并从中选取最佳的根节点
// params[in]:
//            l     中序遍历数组的左边界
//            r     中序遍历数组的右边界
//            p     该中序遍历的父节点
int dp(int l, int r, int p)
{
    if(l>r) return 0;
    if(f[l][r][p]!=-1) return f[l][r][p];
    int ret = 2e9;
    
    // 遍历可能的根节点
    for(int i=l; i<=r; i++)
    {
        int left=dp(l,i-1,i);
        int right=dp(i+1,r,i);
        ret = min(ret, left+right+w[i]*w[p]);
    }
    
    f[l][r][p] = ret;
    return ret;
}

int main()
{
    cin>>n;
    memset(f,-1,sizeof(f));
    for(int i=1;i<=n;++i)
    {
        cin>>w[i];
    }
    cout<<dp(1,n,0);
    return 0;
}

LeetCode 111 二叉树的最小深度

这一题用BFS来解,参考该链接,先给出BFS的算法框架:

int BFS(Node* start, Node* target)
{
	queue<Node*> q;
	set<Node*> visited;
	
	q.push(start);
	visited.insert(start);
	int step=0;
	while (!q.empty())
	{
		int sz = q.size();
		// 将当前队列中的所有节点向周围扩散
		for(int i=0;i<sz;++i)
		{
			Node* cur = q.front();
			q.pop(); //注意这里要pop掉,这一层关系的找完了已经
			// 判断cur是否是要找的终点,若是则返回
			if(cur == target) return step;
			// 将cur的相邻节点加入队列
			for(Node* x: cur.adj())
			{
				if(!(visited.find(x)!=visited.end()))
				{
					q.push(x);
					visited.insert(x);
				}
			}
			// 更新步数
			step++;
	}
}

其实BFS和二叉树的层次遍历是相似的。
接着就可以根据框架给出解题代码了:

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    int minDepth(TreeNode* root) {
        if (root == nullptr) return 0;
        queue<TreeNode*> q;
        q.push(root);
        int depth=1;

        while(!q.empty())
        {
            int sz=q.size();
            for(int i=0;i<sz;i++)
            {
                TreeNode* cur = q.front();
                q.pop();
                if(cur->left == nullptr && cur->right ==nullptr)
                {
                    return depth;
                }
                if(cur->left!=nullptr) q.push(cur->left);
                if(cur->right!=nullptr) q.push(cur->right);
            }
            depth++;
        }
        return depth;
    }
};
C++ STL中的队列queue
  • 需要的头文件: <queue>
  • 怎么用: queue<元素类型> 队列名``queue<int> q;
  • 基本操作:
  1. 入队: q.push(x),将x接到队列的尾部
  2. 出队: q.pop();,弹出队列的第一个元素,但是不会返回那个被弹出的元素的值
  3. 访问队首元素:q.front(),这个可以拿到队首的元素
  4. 访问队尾元素:q.back(),拿到队尾的元素
  5. 判断队列是否为空,q.empty()如果队列为空,就返回true
  6. 访问队列中的元素,q.size()
C++ STL中的unordered_map
  • 需要的头文件:<unordered_map>
  • 内部实现是一个哈希表。哈希表的建立比较费时间,但是查找很方便。此外,遍历的顺序和输入的顺序不一定相同,因为哈希表遍历是从前往后依次遍历的。
  • 怎么用?
    unordered_map<string, string> umap{ {"小明","gege"}, {"小王","jiejie"}, {"小常","shushu"}};建立的时候就可以初始化。
  • 常用操作:
  1. 通过迭代器拷贝其他的unordered_map
    std::unordered_map<std::string, std::string> umap2(++umap.begin(),umap.end());除了umap的第一个元素,其他都复制过去了
  2. 插入键值对:umap.insert({{key,value},{key,value}});,有一个效率更高的选择:umap.emplace(key,value);
  3. 删除指定键值对:umap.erase(key);
C++ STL中的set
  • 包含的头文件: #include<set>
  • 是什么?存储统一数据类型的数据结构,在set中每一个元素的值都是唯一的,此外,系统可以根据元素的值自动排序。底层结构是红黑树。
  • 怎么用?
    > set<int> s;
  • 常用的方法:
  1. s.begin(): 返回set容器的第一个元素
  2. s.end():返回最后一个元素
  3. s.insert(元素):插入元素
  4. s.find(元素):返回给定值的定位器,如果没找到则返回end()

leetcode 654 最大二叉树

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

FLOWVERSE

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值