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