树
一些报错
1.error: non-void function 'inorderTraversal' should return a value [-Wreturn-type]
递归写法应该return什么,应该return一个vector?
2.no matching member function for call to 'push'
原因设置stack的类型为(treenode) 应该为(treenode*)
各种遍历
public:
vector<int> inorderTraversal(TreeNode* root) {
if (!root) {
return;
}
vector<int> res;//建立要返回的数组
inorder(root,res);//函数
return res;//返回一个数组
}
void inorder(TreeNode* root,vector<int>&res ){
if(!root) return ;//递归
inorder(root->left,res);res.push_back(root->val);//中序
inorder(root->right,res);
}
前序非递归
void inorder(TreeNode* root,vector<int>&res ){
stack<TreeNode*> s;
s.push(root);
while(!s.empty()){
root=s.top();
s.pop();
res.push_back(root->val);// 如果是n叉树 就使用for(int i=root->children.size();i>=0;i--) 遍历children[i]
if(root->right) s.push(root->right);//先押入右结点再左 这样弹出就是先弹左结点
if(root->left) s.push(root->left);
}
}
后序非递归
stack<TreeNode*>s1;//两个数占 一个用来输出
stack<TreeNode*>s2;
s1.push(root);
while(!s1.empty()){
root=s1.top();
cout<<root->val;
s2.push(root);
s1.pop();if(root->left) s1.push(root->left);//先左后右
if(root->right) {s1.push(root->right);}
}
while(!s2.empty()){
res.push_back(s2.top()->val);
s2.pop();
}
中序非递归
//这里不需要提前放入head,否者会重复操作
stack<TreeNode*>s;
while(!s.empty()||root){
if(root)//无论是让root等于左子树还是右子树,都需要判断
{
s.push(root);
root=root->left;
}
else{
root=s.top(); //每次抽出栈,让这个root暂时保存
res.push_back(root->val);
s.pop();
root=root->right;//让这个root等于右子树再遍历左子树
}
}
使用统一的迭代法
s.push(root);
while(!s.empty()){
root=s.top();
if(root){
s.pop();//看到了,但未处理,先抽出等下再翻进去
if(root->right) s.push(root->right);
s.push(root);s.push(nullptr);//这两句话一定不能变,变了就不对了!!
//思路在每次null,则是要处理的root的时候压入数组,
if(root->left) s.push(root->left);
}else{//当看到null则是真正的
s.pop();
root=s.top();
s.pop();
res.push_back(root->val);
}
树的层序遍历
vector<vector<int> >res;//定义一个vector 存放vector的数据 表示每一层
if(!root) return res;
queue<TreeNode*>q;
q.push(root);
while(!q.empty()){
vector<int>cur;
int size=q.size();//根据二叉树的性质,size记住当前队列还有的元素个数,用于抽出元素,当超过这个数据的时候
for(int i=0;i<size;i++){//一层一层的来
root=q.front();
q.pop();//使用队列,先进先处理符合层序遍历
cur.push_back(root->val);//
if(root->left) q.push(root->left); //放左和放右
if(root->right) q.push(root->right);
}
res.push_back(cur);//每一层都进行结算
}
return res;
树的右视图dfs法
vector<int> rightSideView(TreeNode* root) {
int depth=1;
if(!root) return res;
dfs(root,0);
return res;
}
void dfs(TreeNode* root,int depth){
if(!root) return ;
if(depth==res.size()){//res里面存放的个数对应的是第几层 第一层就放第一个 永远放第一个
res.push_back(root->val);当第一次发现depth,就放 ,放完res++,后面的depth不会满足所以进不了,实现首个的母的
}
depth++;//每次进入这个函数depth都会计数,木的是为了下面的dfs
dfs(root->right,depth) ;
dfs(root->left,depth) ;
}
N叉树
class Node{
int val;
vector<Node*> children;//用一个指针数组保存
}
vector<vector<int> >res;if(!root) return res;
queue<Node* >q;
q.push(root);
while(!q.empty()){
int size=q.size();
vector<int>v ;
for(int i=0;i<size;i++){
root=q.front();
q.pop();
v.push_back(root->val);
// s+=root->val;
for(int i=0;i<root->children.size();i++)//这样做
if(root->children[i]) q.push(root->children[i]);//使用下标
}
res.push_back(v);
}return res;
连接结点的下一个右侧节点
while(!q.empty()){
int size=q.size();
Node* pre;
pre=q.front();
for(int i=0;i<size;i++){
Node* cur;//两个结点一个前,一个后
if(i==0){cur=q.front();//取出每层首个结点
pre=q.front();
}
else{cur=q.front();//next指过去
pre->next=cur;pre=pre->next;//走一步
}
q.pop();
if(cur->left) q.push(cur->left);
if(cur->right) q.push(cur->right);
if(i==size-1){//当是最后一个的时候记得补上右节点为null
pre->next=NULL;
}
}
}return root;
连接右结点递归版本
Node* connect(Node* root) {
if(!root) return root;
if(root->left){//把下一层处理好
root->left->next=root->right;
if(root->next) root->right->next=root->next->left;//连接
}
connect(root->left);
connect(root->right);//递归
return root;
}
树的镜面对称(递归的比较使用)
bool cmp(TreeNode* left,TreeNode * right){//递归比较函数
//注意递归结束的条件
if(!left&&!right) return true;//同时为空的时候也是真
else if(!right||!left) return false;//当右边为空而左边不是的时候 false 100.00%
else if(left->val!=right->val) return false;//注意做错[1,2,3]是因为少了这个没有处理值不相等的情况
else{//还会有一种情况
bool a=cmp(left->left,right->right);
bool b=cmp(left->right,right->left);
bool c=a&&b;
return c;
}
递归判断子树
bool isSubtree(TreeNode* root, TreeNode* subRoot) {
if(cmp(root->left,subRoot)||cmp(root->right,subRoot))return false;//这样写不会递归;
bool isSubtree(TreeNode* root, TreeNode* subRoot) {
// if(cmp(root->left,subRoot)||cmp(root->right,subRoot))return false;//这样写不会递归
if(!root&&!subRoot) return true;
if(!root||!subRoot) return false;
if(cmp(root,subRoot)) return true;
return isSubtree(root->left,subRoot)||isSubtree(root->right,subRoot);//判断不出来就继续递归!!!
}
bool cmp(TreeNode* p,TreeNode* q){一个比较函数
if(!p&&!q) return true;//
else if(!p||!q) return false;
else if(p->val!=q->val) return false;
else {
return cmp(p->left,q->left)&&cmp(p->right,q->right );
}
n叉树的深度
int getdepth(*node root)
if(!root) return 0;
int m=0;
for(int i=0;i<root->children.size();i++){
m=max(m,getdepth(root->children[i]));//从左到右保存最大的就是
}
return m+1;//算上自本身
求树的节点个数 递归 看成将叶子结点也看成完全二叉树 o(logn)
int countNodes(TreeNode* root) {//
if (root == nullptr) return 0;//关键!看懂这段代码首先设置只有一个结点的时候发现函数返回值是2<<0-1=1,所以后面都按这个走
TreeNode* left = root->left;//好像只能这么简单所有left换成left->left不能换成
TreeNode* right = root->right;
int leftHeight = 0, rightHeight = 0; // 这里初始为0是有目的的,为了下面求指数方便
while (left) { // 求左子树深度,一直往左走,
left = left->left;
leftHeight++;
}
while (right) { // 求右子树深度,一直往右走
right = right->right;
rightHeight++;
}
if (leftHeight == rightHeight) {//当左边高度等于右边的时候,选一边进行 使用2
return (2 << leftHeight) - 1; // 注意(2<<1) 相当于2^2,所以leftHeight初始为0,特判相当于简便了计算而不是递归求结点了
}//左边不等于右边,各自分一个
return countNodes(root->left) + countNodes(root->right) + 1;//如果右边没有,左边有会发现右边返回值是0
求深度可以从上到下去查 所以需要前序遍历(中左右)第一个是中,
而高度只能从下到上去查,所以只能后序遍历(左右中)最后一个是中,
判断完全二叉树
bool isBalanced(TreeNode* root) {
if(!root) return true;
if(gethight(root)!=-1)
return true;
return false;
}
int gethight(TreeNode *root){使用-1,始终保存-1 的值
if(!root) return 0;//叶子节点
int left=gethight(root->left);//左结点
int right=gethight(root->right);//获取右结点的值
if(left==-1) return -1;//当等于-1说明已经不是一个完全二叉树了 直接返回
if(right==-1) return -1;
if(abs(left-right)>1) return -1;//如果左边右边大于1说明不是二叉树 返回-1
else return 1+max(right,left);//返回值是为了计算高度 +1算上了自己
}
获得二叉树所有路径
vector<string> binaryTreePaths(TreeNode* root) {
vector<string > res;
vector<int >path;//两个vector 一个存入值一个存入答案
if(!root) return res;
traversal(root,path,res);
return res;
}
void traversal(TreeNode * cur ,vector<int>&path ,vector<string>&res ){
path.push_back(cur->val);//中序遍历 进来先存入值
if(!cur->left&&!cur->right){如果是叶子结点
string s;
for(int i=0;i<path.size()-1;i++){//为了让最后一个->符号合理
s+=to_string(path[i]);
s+="->";
}
s+=to_string(path[path.size()-1]);//使用string转话为数字的函数to_string(int val)
res.push_back(s);
return ; }
if(cur->left) {
traversal(cur->left,path,res) ;path.pop_back();//回溯消去之前递归加入了那个值
}
if(cur->right) {
traversal(cur->right,path,res) ;path.pop_back();//使用pop back
}
}
递归精简版
void count(TreeNode *root,string path,vector
path+=to_string(root->val);
if(!root->left&&!root->right){
res.push_back(path);
return ;
}
if(root->left) {
count(root->left,path+"->",res) ;
}
if(root->right) {
count(root->right,path+"->",res) ;//使用path+->而不是path+= 否则会改变了
}
}
迭代
vector
stack<TreeNode > treest;//存迭代
stack
vector
if(!root) return res;
treest.push(root);
pathst.push(to_string(root->val));
while(!treest.empty()){
TreeNode
string path=pathst.top();pathst.pop();//用于存放string的值,不用在存入中结点也是这个理由
if(!node->left&&!node->right){
res.push_back(path);
}
if(node->right){
treest.push(node->right);
pathst.push(path+"->"+to_string(node->right->val));
}
if(node->left){
treest.push(node->left);
pathst.push(path+="->"+to_string(node->left->val));//传入的是path+“->”+值的这个字符串
}
}
return res;
统计左叶子节点之和: 首先你得知道怎么判断是不是左叶子结点 :只能通过该节点的父结点判断是不是叶子节点
if(root->left&&!root->left>right&&!root->left->right
如果需要遍历整颗树,递归函数就不能有返回值。如果需要遍历某一条固定路线,递归函数就一定要有返回值!
找最后一层的左叶子的值
int maxlength=INT_MIN;//两个全局变量
int value;
int findBottomLeftValue(TreeNode* root) {
travelsal(root,0);
return value;
}
void travelsal(TreeNode* root,int leftlen){
if(!root->left&&!root->right) if(leftlen>maxlength){//到达了叶子结点并且深度大于最大深度
value=root->val;..更新值
maxlength=leftlen;
}
if(root->left) travelsal(root->left,leftlen+1) ;//先左边后右边,自带回溯
if(root->right) travelsal(root->right,leftlen+1);
}
路经总和
bool hasPathSum(TreeNode* root, int targetSum) {
if(dfs(root,targetSum)==-1) return true;//-1表示真
return false;//
}
int dfs(TreeNode * root,int targetSum){
if(!root) return 0;//
targetsum-=root->val;//当减到0而且是叶子结点就好
if(targetSum==0&&!root->left&&!root->right) return -1;//加完之后相等就return-1
if(dfs(root->left,targetSum)==-1) return -1;//传值自带回溯
if(dfs(root->right,targetSum)==-1) return -1;
return 0;
}
bool haspathsum(treenode* root, int sum) {
if (root == null) return false;
if (!root->left && !root->right && sum == root->val) {//传入值 若值相等
return true;
}
return haspathsum(root->left, sum - root->val) || haspathsum(root->right, sum - root->val);//,传的是相减的,只要有一边成功就可以
}
bool hasPathSum(TreeNode* root, int targetSum) {
if(!root) return false;
stack<pair<TreeNode*,int> >s;//只要是pair都必须带个<元素类型,元素类型>
s.push(pair<TreeNode*,int>(root,root->val) );
while(!s.empty()){前序遍历
pair<TreeNode*,int>node=s.top();s.pop();
if(!node.first->left&&!node.first->right&&node.second==targetSum) return true;
if(node.first->right) s.push(pair<TreeNode*,int>(node.first->right,node.second+node.first->right->val));
if(node.first->left) s.push(pair<TreeNode*,int>(node.first->left,node.second+node.first->left->val));
}
return false;
vector<vector<int> >res;
vector<int> path;//全局变量 path记录结点 常用
vector<vector<int>> pathSum(TreeNode* root, int targetSum) {
if(!root) return res;
path.push_back(root->val);//
dfs(root ,targetSum-root->val);//传入一个根节点 传入一个值即可
return res;
}
void dfs(TreeNode* root,int count){
if(!root->left&&!root->right&&count==0) {//count==0,return
res.push_back(path);return;
}
if(root->left){ path.push_back(root->left->val);
dfs(root->left,count-root->left->val);
path.pop_back();//记得放入和拿出path
}
if(root->right){
path.push_back(root->right->val);
dfs(root->right,count-root->right->val);
path.pop_back();
}return ;
}
TreeNode* traversal (vector<int>& inorder, vector<int>& postorder) {
// 第一步
if (postorder.size() == 0) return NULL;//如果数组没有值说明已经没有了值,即空
// 第二步:后序遍历数组最后一个元素,就是当前的中间节点或叶子节点
int rootValue = postorder[postorder.size() - 1];//int 变量存中间结点的值,方便后面的建立,或者返回叶子结点
TreeNode* root = new TreeNode(rootValue);//
// 叶子节点
if (postorder.size() == 1) return root;//数组元素只有上面这一个 说明是叶子结点可以直接return
// 第三步:找切割点
int delimiterIndex;//分割点
for (delimiterIndex = 0; delimiterIndex < inorder.size(); delimiterIndex++) {
if (inorder[delimiterIndex] == rootValue) break;//在中序数组里面找,找到就直接退
}
// 第四步:切割中序数组,得到 中序左数组和中序右数组
// 左闭右开区间:[0, delimiterIndex)
vector<int> leftInorder(inorder.begin(), inorder.begin() + delimiterIndex);
// [delimiterIndex + 1, end)//左闭右开 靠后面右边的不会包括
vector<int> rightInorder(inorder.begin() + delimiterIndex + 1, inorder.end() );
// 第五步:切割后序数组,得到 后序左数组和后序右数组
//此时有一个很重的点,就是中序数组大小一定是和后序数组的大小相同的(这是必然)。
// postorder 舍弃末尾元素,因为这个元素就是中间节点,已经用过了
postorder.resize(postorder.size() - 1);//重新设置大小
// 左闭右开,注意这里使用了左中序数组大小作为切割点:[0, leftInorder.size)//
vector<int> leftPostorder(postorder.begin(), postorder.begin() + leftInorder.size());//迭代器加数字
// [leftInorder.size(), end)
vector<int> rightPostorder(postorder.begin() + leftInorder.size(), postorder.end());//不用+1因为需要这个数
// 第六步
root->left = traversal(中序左数组, 后序左数组);//递归
root->right = traversal(中序右数组, 后序右数组);//
return root;
}
```上面的优化 就是递归的时候传引用 然后 定义几个数组 保存各个边界从而达到不多次使用vector的效果
##使用直接传引用数组的话 利用下表索引 从14->92 的击败时间
TreeNode* constructMaximumBinaryTree(vector
return dfs(nums,0,nums.size());
}
TreeNode* dfs(vector<int> &v ,int left,int right ){
if(left>=right) return nullptr;
// if(v.size()==1) return new TreeNode(v[0]);
int p=left;
for(int i=left+1;i<right;i++){
if(v[p]<v[i]) {
p=i;
}
}
TreeNode * node=new TreeNode(v[p]);
node->left=dfs(v,left,p);
node->right=dfs(v,p+1,right);
return node;
}
##合并二叉树
class Solution {
public:
TreeNode* mergeTrees(TreeNode* t1, TreeNode* t2) {
if (t1 == NULL) return t2;
if (t2 == NULL) return t1;
queue<TreeNode> que;
que.push(t1);//要押入一起压入
que.push(t2);
while(!que.empty()) {
TreeNode node1 = que.front(); que.pop();
TreeNode* node2 = que.front(); que.pop();//要压入一起压入,要处理一起处理,但栈的抽出之后不会影响树的任何东西
// 此时两个节点一定不为空,val相加
node1->val += node2->val;//以左边的树为基准,改变他的东西,相当于一次处理一个结点,虽然弄了两次
//结点上面的部分已经处理好了,不需要再看一下了,下面已经是对子树的处理了
// 如果两棵树左节点都不为空,加入队列
if (node1->left != NULL && node2->left != NULL) {//因为两个左树都不为空,所以要处理一下,让两个子树进去
que.push(node1->left);
que.push(node2->left);
}
// 如果两棵树右节点都不为空,加入队列
if (node1->right != NULL && node2->right != NULL) {//因为两个右边的树不为空,所以要处理下,让两个右边进去
que.push(node1->right);
que.push(node2->right);
}
// 当t1的左节点 为空 t2左节点不为空,就赋值过去
if (node1->left == NULL && node2->left != NULL) {
node1->left = node2->left;//因为有空的 ,所以直接弄就好了,不需要使用队列
}
// 当t1的右节点 为空 t2右节点不为空,就赋值过去
if (node1->right == NULL && node2->right != NULL) {
node1->right = node2->right;//因为有空的 ,直接弄,并不需要队列,不需要传入
}
}
return t1;//将tree1作为了答案
}
};
```注意:只是做左边的值的修改!!
TreeNode* mergeTrees(TreeNode* root1, TreeNode* root2) {
if(!root1) return root2;if(!root2) return root1;//如果一个为空就返回另一个,如果另一个也为空也是满足的
root1->val+=root2->val;//将值相加
root1->left=mergeTrees(root1->left,root2->left);//继续传入双方的左边
root1->right=mergeTrees(root1->right,root2->right);
return root1;
}