算法day15|513.找树左下角的值、112. 路径总和、113.路径总和Ⅱ、106.从中序与后序遍历序列构造二叉树、105.从前序与中序遍历序列构造二叉树

算法day15|513.找树左下角的值、112. 路径总和、113.路径总和Ⅱ、106.从中序与后序遍历序列构造二叉树、105.从前序与中序遍历序列构造二叉树

  • 513.找树左下角的值
    • 迭代法
  • 112. 路径总和
  • 113.路径总和Ⅱ
  • 106.从中序与后序遍历序列构造二叉树
  • 105.从前序与中序遍历序列构造二叉树

513.找树左下角的值

一开始题意理解错了,做了好多无用功…看来读题真的非常重要。以为重点是左下角,其实题目的中的左下角必须是在最后一层。即使最后一层没有左孩子结点,只有右孩子结点,那么这个右孩子也算是树的左下角。

迭代法

class Solution {
public:
    int findBottomLeftValue(TreeNode* root) {
        queue<TreeNode*> que;
        que.push(root);
        int result;
        while(!que.empty())
        {
            int size=que.size();
                for(int i=0;i<size;i++)
                {
                TreeNode*node=que.front();
                que.pop();
                if(i==0) result=node->val;
                if(node->left) que.push(node->left);
                if(node->right) que.push(node->right);
                }
        }
        return result;
    }
};

迭代法我一开始也没有做出来,主要还是因为不知道该怎么去定位最后一层,我该凭什么逻辑来认定它就是最后一层呢?然后陷进去出不来了。而卡哥的解法非常巧妙:我们不管什么时候是最后一层,我先把一层里面第一个值赋给result。这样的话,第一层的第一个值赋给result,等到了的二层的时候机会自动更新为第二层的第一个值,第三层的时候以此类推… 所以当到了最后一层的时候,result就是最后一层的第一个值。只有对过程和结果的理解非常深刻才能想到这个。我们不单单看着最后一层,我们看到是整个逻辑过程

另外,除非思路贴吧清晰,否则不要使用while(n–),而要改用for(int i=0;i

112. 路径总和

这题还是比较简单的,代码如下:

class Solution {
public:
    void traversal(TreeNode*root,vector<int>&path,vector<int>& result)
    {
        path.push_back(root->val);
        if(root->left==nullptr&&root->right==nullptr)
        {
            int count=0;
            for(int i=0;i<path.size();i++)
            count+=path[i];
            result.push_back(count);
            return;
        }
        if(root->left)
        {
            traversal(root->left,path,result);
            path.pop_back();
        }
        if(root->right)
        {
            traversal(root->right,path,result);
            path.pop_back();
        }
    }
    bool hasPathSum(TreeNode* root, int targetSum) {
        vector<int> path;
        vector<int> result;
        int flag=false;
        if(root!=nullptr)
        {
            traversal(root,path,result);
            for(int i=0;i<result.size();i++)
            {
                if(result[i]==targetSum)
                flag=true;
            }
        }
        return flag;
    }
};

这题思路和257.二叉树的所有路径基本一致,只是把其中的一个字符串型数组改成了整数型数组,核心逻辑完全相同,属于模板题。

113.路径总和Ⅱ

这题同样很简单,只需要再加一个二位数组来接收一下路径即可。具体代码如下:

class Solution {
public:
void traversal(TreeNode*root,vector<int>&path,vector<int>& result,vector<vector<int>>&Path)
    {
        path.push_back(root->val);
        if(root->left==nullptr&&root->right==nullptr)
        {
            Path.push_back(path);
            int count=0;
            for(int i=0;i<path.size();i++)
            count+=path[i];
            result.push_back(count);
            return;
        }
        if(root->left)
        {
            traversal(root->left,path,result,Path);
            path.pop_back();
        }
        if(root->right)
        {
            traversal(root->right,path,result,Path);
            path.pop_back();
        }
    }
    vector<vector<int>> pathSum(TreeNode* root, int targetSum) {
        vector<int> path;
        vector<int> result;
        vector<vector<int>> Path;
        vector<vector<int>> Result;
        if(root!=nullptr)
        {
            traversal(root,path,result,Path);
            for(int i=0;i<result.size();i++)
            {
                if(result[i]==targetSum)
                Result.push_back(Path[i]);
            }
        }
        return Result;
    }
};

106.从中序与后序遍历序列构造二叉树

这题难度很大,而且其中的vector的用法我也是第一次见,一共花了一个多小时才弄明白,具体代码如下:

class Solution {
public:
    TreeNode*traversal(vector<int>& inorder, vector<int>& postorder)
    {
        if(postorder.size()==0) 
        return nullptr;
        int value=postorder[postorder.size()-1];
        TreeNode*root=new TreeNode(value);
        if(postorder.size()==1) 
        return root;
        int index=0;
        for(;index<inorder.size();index++)
        {
            if(inorder[index]==value) 
            break;
        }
        
        vector<int>leftInorder(inorder.begin(),inorder.begin()+index);
        vector<int>rightInorder(inorder.begin()+index+1,inorder.end());
        
        postorder.resize(postorder.size()-1);
        
        vector<int>leftPostorder(postorder.begin(),postorder.begin()+leftInorder.size());
        vector<int>rightPostorder(postorder.begin()+leftInorder.size(),postorder.end());
        
        root->left=traversal(leftInorder,leftPostorder);
        root->right=traversal(rightInorder,rightPostorder);
        
        return root;
    }

    TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder)
    {
        if(!inorder.empty())
        return traversal(inorder,postorder);
        else
        return nullptr;
    }
};

总体思路(递归):

  • 参数显然是中序数组和后序数组,返回值是结点类型(这意味肯定有函数赋值的操作)

  • 终止条件,有2个:一是当后续数组为空时(每递归依次后序数组大小都会减一),返回null,比较正常;二是当后续数组只有一个元素时,直接返回root;(可以理解成剪枝的操作)

  • 单层递归:

    • 首先,先序遍历,创造当前结点空间并赋值(从当前节点往下走,因为孩子的递归需要父节点的信息,如怎么去切割,所有要先序遍历)。

    • 然后就是重头戏:为当前的左右孩子分别切割左右中序和左右后续

      • 先切割原来的中序数组。具体方法:定义两个vector数组,把左边的数组赋值到一个vector中,再把右边的数组赋值到另一个vector中;
      • 然后再切割后续数组。具体方法:把前面的和左中序相同大小的数组赋值到一个vector中,再把剩余的数组赋值到另一个vector中(在切割需要将原后序数组的大小减一)
      • 要注意,切割的时候要保证区间的统一,要么都是左开右闭,要不都是左闭右开等等,看情况选择一个,之后所有的区间都是按照这一个逻辑进行
    • 切割完成之后,给左孩子分配左中序和左后序,给右孩子分配有右中序和右后序,递归

    • 最后别忘了返回当前结点

105.从前序与中序遍历序列构造二叉树

class Solution {
public:
    TreeNode*traversal(vector<int>& preorder, vector<int>& inorder)
    {
        if(preorder.size()==0)
        return nullptr;
        int value=preorder[0];
        TreeNode*root=new TreeNode(value);
        if(preorder.size()==1)
        return root;
        int index=0;
        for(;index<inorder.size();index++)
        {
            if(inorder[index]==value)
            break;
        }
        vector<int> leftInorder(inorder.begin(),inorder.begin()+index);
        vector<int> rightInorder(inorder.begin()+index+1,inorder.end());
        preorder.erase(preorder.begin());
        vector<int> leftPreorder(preorder.begin(),preorder.begin()+leftInorder.size());
        vector<int> rightPreorder(preorder.begin()+leftInorder.size(),preorder.end());
        root->left=traversal(leftPreorder,leftInorder);
        root->right=traversal(rightPreorder,rightInorder);
        return root;
    }
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        if(!preorder.empty())
        return traversal(preorder,inorder);
        else 
        return nullptr;
    }
};

原理基本相同,唯一不同的是先序数组要先删除第一个元素,而前面一题是删除最后一个元素。即preorder.erase(preorder.begin())。此函数内部包含了删除之后的数组位置的重新布置以及size–

你可能感兴趣的:(算法,数据结构,c++,leetcode)