【leetcode刷题日记】树

树一般涉及到递归,回溯,剪枝,深度优先/栈,广度优先/队列,三种遍历方式。树的递归都是一样的套路,首先判断 最下方叶节点 和 根节点为空 的情况,这两个的代码或者情景实际上是一样的,然后判断左右子树对应的某个结点,这两个结点各自的子树也有相同的关系。这样就实现了递归。

对递归的两种理解:
前序递归:每次先对当前结点操作一下,再往左子树慢慢下去,右子树慢慢下去;
中序遍历:先往左子树跑到头,然后依次返回各个结点,右子树慢慢下去;
后序遍历:先往左子树跑到头,然后依次返回各个结点,再跑右子树跑到头,然后依次返回各个结点。
或者每次看到递归,可以认为它把子树都处理完了。

深度相关:有用栈的,大部分用递归。
二叉搜索树相关:看到就用中序遍历!
回溯相关:回溯解决的是全排列问题。257题,注意,回溯很多题都要用一个辅助函数。回溯题专讲请见另一篇文章(6大步骤团灭回溯题)。
广度优先相关:队列

100.相同的树 简单

给定两个二叉树,编写一个函数来检验它们是否相同。如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。

class Solution {
public:
    bool isSameTree(TreeNode* p, TreeNode* q) {
        //这个判断针对 叶节点的下一轮 或 光杆根节点
        if(p==nullptr && q==nullptr) return true;
        //判断当前结点
        if(p&&q && p->val==q->val){ //<- p&&q这个判断一定要有,上一个条件不能排除空结点的情况
            //如果 左子树 和 右子树 都相同
            if(isSameTree(p->left,q->left) && isSameTree(p->right,q->right)){
                return true;
            }
        }
        return false;
    }
};

这道题没什么好说的,一般递归都会有对 当前结点 和 左右子树 分别的操作,同时需要在开头考虑叶节点的情况。最近碰到好几次下面的报错:
runtime error: member access within null pointer of type ‘struct TreeNode’
需要加上代码中标红的判断。

对于递归的理解:
看到isSameTree(p->left,q->left)之后,我们不用去思考复杂的递归过程,而仅仅把它当成另一个封装完全有独立功能的函数。有这个语句之后,我就知道,它的子树,也满足这条件。

101.对称二叉树 简单

1

/
2 2
/ \ /
3 4 4 3

class Solution {
public:
    bool isSymmetric(TreeNode* root) {
        return isSymmetric(root,root);
    }
private:
    bool isSymmetric(TreeNode* left,TreeNode* right){
        if(left==nullptr && right==nullptr) return true;
        if(left==nullptr || right==nullptr) return false;
        return (left->val==right->val) && isSymmetric(left->left,right->right) && isSymmetric(left->right,right->left);
    }
};

哎,这道题卡了我很久,之前想了个层序遍历的不对。
这个递归的,思路是比较左子树和右子树,左子树的根节点和右子树的根节点的val相同,而且左子树的左侧与右子树法右侧相同,左子树的右侧和右子树的左侧相同。

104.二叉树的最大深度 简单

class Solution {
public:
    int maxDepth(TreeNode* root) {
        int num(0);
        if(!root) return num;
        if(root->left) num = max(num, maxDepth(root->left));
        if(root->right) num = max(num, maxDepth(root->right));
        num++;
    return num;
    }
};

树的最大深度 = max(左子树深度,右子树深度) + 1;
还是一样的,先考虑 根节点为空 或 叶节点 的情况,在考虑左子树和右子树。
有一个化简的写法:

    int maxDepth(TreeNode *node){
        if(!node) return 0;
        return max(maxDepth(node->left), maxDepth(node->right)) + 1;
}

559.N叉树的最大深度

class Solution {
public:
    int maxDepth(Node* root) {
        int maxi = 0;
        if(!root) return 0;
        //找出所有子树中最高的那个的长度
        for(Node* it:root->children){
            if(it) maxi = max(maxi,maxDepth(it));
        }
        //树的长度等于最高的子树的长度+1
        return maxi+1;
    }
};

和104题一样。

107.二叉树的层序遍历 II 简单

给定一个二叉树,返回其节点值自底向上的层次遍历。 (即按从叶子节点所在层到根节点所在的层,逐层从左向右遍历)

class Solution {
public:
    vector<vector<int>> levelOrderBottom(TreeNode* root) {
        vector<vector<int>> result;
        if(!root) return result;
        stack<vector<int>> temp;
        int level = 0;
        vector<int> item;
        queue<pair<int,TreeNode *>> que;
        que.push(make_pair(level,root));
        while(!que.empty()){
            int last_level = level;//当前的层数
            level++; //下一层的层数
            item.clear();
            while(que.front().first==last_level){
                TreeNode *node = que.front().second;
                que.pop();
                if(!node) continue;//这一句能提高性能
                if(node) item.emplace_back(node->val);
                if(node && node->left) que.push(make_pair(level,node->left));
                if(node && node->right) que.push(make_pair(level,node->right));
            }
            temp.push(item);
        }
        while(!temp.empty()){
            result.emplace_back(temp.top());
            temp.pop();
        }
        return result;
    }
};

既然是层序遍历,而且是从下往上输出,很快就能想到用栈。101那道题做不对,就是因为当时没有用last_level这个策略。要想一层一层的操作,那么肯定就需要make_pair (level,root) 来记录层数。在添加当前层的左右孩子进队列的时候,层数需要加一。不过可能有的有左孩子有的有右孩子有的都有有的都没有,如果层数在make_pair (level++,node->left))添加的话,会出现混乱,所以得在这个while外面添加。或者不用level++,在括号里用level+1.

108. 将有序数组转换为二叉搜索树 简单

将一个按照升序排列的有序数组,转换为一棵高度平衡二叉搜索树。本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1。

class Solution {
public:
    TreeNode* sortedArrayToBST(vector<int>& nums) {
        if(nums.size()==0) return nullptr;
        return sortedArrayToBST(0,nums.size()-1,nums);
    }
private:
    TreeNode* sortedArrayToBST(int start, int end, vector<int>& nums){
        if(start>end) return nullptr;
        int mid = (start + end) / 2; //用>>提升性能
        TreeNode* node = new TreeNode(nums[mid]);
        //这样可千万不行:TreeNode node(nums[mid])!!在栈上,出来就析构了。
        TreeNode* left = sortedArrayToBST(start, mid-1, nums);
        TreeNode* right = sortedArrayToBST(mid+1, end, nums);
        node->left = left;
        node->right = right;
        return node;
    }
};

犯了个老错误,开辟新空间的时候,在自由存储区new一个,不要在栈上开辟。离开作用域就析构了。这道题跟二叉排序很像。

110 判断一棵树是否是平衡二叉树 简单

错误的解答:

class Solution {
public:
    bool isBalanced(TreeNode* root) {
        if(!root) return true;
        int l(0),r(0);
        if(root->left) l = maxDepth(root->left);
        if(root->right) r = maxDepth(root->right);
        return abs(l-r)<2;
    }
private:
    int maxDepth(TreeNode *root){
        int m = 0;
        if(!root) return m;
        if(root->left) m = max(m,maxDepth(root->left));
        if(root->right) m = max(m,maxDepth(root->right));
        return ++m;
    }
};

注意,左右子树的最大深度之差小于1并不能保证这是一颗平衡二叉树。万一左右子树也都不是平衡的呢?
修改:
加上一个判断即可。

class Solution {
public:
    bool isBalanced(TreeNode* root) {
        if(!root) return true;
        int l(0),r(0);
        //if(!isBalanced(root->left)) return false;
        //if(!isBalanced(root->left)) return false;
        l = maxDepth(root->left);
        r = maxDepth(root->right);
        return (abs(l-r)<2) && isBalanced(root->left) && isBalanced(root->right);
    }
private:
    int maxDepth(TreeNode *node){
        if(!node) return 0;
        return max(maxDepth(node->left), maxDepth(node->right)) + 1;
    }
};

花了好长时间啊阿啊阿啊阿啊!
增加判断:除了左右子树最大深度差小于2外,还有左右子树都是平衡二叉树的判断。
而且这道题用上了104题的代码。

111.二叉树的最小深度

一看就是层序遍历。
思路1:使用107题的套路。

class Solution {
public:
    int minDepth(TreeNode* root) {
        if(!root) return 0;
        queue<pair<int,TreeNode*>> que;
        int level(0),last_level(0);
        que.push(make_pair(++level,root));
        while(!que.empty()){
            last_level = que.front().first;
            level = last_level + 1;
            //对当前层元素的操作
            while(last_level==que.front().first){ <-实际上是多余的
                TreeNode* nextNode = que.front().second;
                que.pop();
                if(!nextNode->left && !nextNode->right) return last_level;
                if(nextNode->left) que.push(make_pair(level,nextNode->left));
                if(nextNode->right) que.push(make_pair(level,nextNode->right));
            }
        }
        return last_level;
    }
};

改进:
其实不用2个while。

class Solution {
public:
    int minDepth(TreeNode* root) {
        if(!root) return 0;
        queue<pair<int,TreeNode*>> que;
        int level(0),last_level(0);
        que.push(make_pair(++level,root));
        while(!que.empty()){
            level = que.front().first;
            TreeNode* nextNode = que.front().second;
            que.pop();
            if(!nextNode->left && !nextNode->right) return level;
            if(nextNode->left) que.push(make_pair(level+1,nextNode->left));
            if(nextNode->right) que.push(make_pair(level+1,nextNode->right));
        }
        return last_level;
    }
};

112.树是否存在某条路径使上面所有val的和等于给定值 简单

class Solution {
public:
bool hasPathSum(TreeNode* root, int sum) {
	 //针对输入为空 或者 叶节点的下一层(也就是nullptr)
        if(!root) return false;
//针对 叶节点
        if(!root->left && !root->right && sum==root->val) return true;
		 //针对 子路径,(可以发现顺序是自下而上的)
        if(root->left && hasPathSum(root->left,sum-root->val)) return true;
        if(root->right && hasPathSum(root->right,sum-root->val)) return true;
        return false;
    }
};

警惕!很多题判断sum的,都是采用减法而不是加法。如果采用加法,逻辑不好控制,还需要辅助函数。
并没有用到回溯。每经过一个结点,sum就减去一个值,如果遇到根节点了,剩余数值正好等于了叶节点的值,那么就true。

递归方式,
如果这个树存在一条路径路径等于sum,那么他就存在一条子路径等于sum-root->val。

226. 翻转一棵二叉树 简单

class Solution {
public:
    TreeNode* invertTree(TreeNode* root) {
        TreeNode* newTree = new TreeNode(0);
        return invertTree(newTree,root);
    }
private:
    TreeNode* invertTree(TreeNode* newTree,TreeNode* root){
        //针对 空的root 和 叶节点指向的nullptr
        if(!root) return nullptr;
        //针对 叶节点
        newTree->val = root->val;
        //针对 右子树
        if(root->right){
            TreeNode* left = new TreeNode(0);
            newTree->left = invertTree(left,root->right);
        }
        //针对 左子树
        if(root->left){
            TreeNode* right = new TreeNode(0);
            newTree->right = invertTree(right,root->left); 
        }
        return newTree;       
    }
};

造一颗新树。下面是答案,纯翻转。java

public TreeNode invertTree(TreeNode root) {
    if (root == null) {
        return null;
    }
    TreeNode right = invertTree(root.right);
    TreeNode left = invertTree(root.left);
    root.left = right;
    root.right = left;
    return root;
}

235.给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先 简单

class Solution {
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        if(p->val<root->val && q->val<root->val) 
return lowestCommonAncestor(root->left, p, q);
        if(p->val>root->val && q->val>root->val) 
return lowestCommonAncestor(root->right, p, q);
        else return root; 
    }
};

看清楚,这是一颗二叉搜索树!!要充分利用他的性质:
如果两个数都小于根节点,那么就在左子树上找;
如果两个数都大于根节点,那么就在右子树上找;
如果两个数一个大于一个小于根节点,那么结果就是根节点了;

257. 二叉树的所有路径 简单

class Solution {
public:
    vector<string> result;
    string item;
    vector<string> binaryTreePaths(TreeNode* root) {
        generate(result,item,root);
        return result;
    }
private:
    void generate(vector<string>& result, string& item, TreeNode* root){
        //对于 空输入 和 叶节点的下一轮, 直接停止递归
        if(!root) return;//item = "", result.emplace_back(item);
        //每次访问结点,都需要增加"->val",不过开头需要单独判断
        //注意int转string的方法
        item += (item.empty()? "":"->") + to_string(root->val);
        //如果到达了叶节点,可以往result里加入一个结果
        if(!root->left && !root->right) result.emplace_back(item);
        //记录回溯前状态
        int len = item.length();
        //对左子树进行操作
        if(root->left){
            //递归
            generate(result,item,root->left);
            //回溯,清除本轮操作的状态,注意对string清除操作的用法
            item.erase(item.begin()+len,item.end());
        }
        if(root->right){
            //递归
            generate(result,item,root->right);
            //回溯,清除本轮操作的状态
            item.erase(item.begin()+len,item.end());
        }
        return;
    }
};

一看就是一道典型的全排列问题,用回溯。我知道,回溯就是清除当前操作,从而复原到之前的状态,以便在原先状态的基础上进行另外的操作;但是我之前总是担心会重复操作。实际上回溯不会重复操作,因为他用的是if,本次操作后就直接进行其它操作了。

如何理解辅助函数?一般它都是void类型,而且它的操作对象,主要还不是总容器vector result(用过引用的方式修改该对象的值),而是当前容器string item。辅助函数内部,首先是极限值判断;然后是递归操作。

在评论区发现了一种更紧凑的写法:

    void backtrack(TreeNode* root) {
        //对于 空输入 和 叶节点的下一轮, 直接停止递归
        if (!root) return;
        //记录回溯前状态
        int len = path.size();  
        //每次访问结点,都需要增加"->val",不过开头需要单独判断
        path += (path.empty() ? "" : "->") + to_string(root->val); 
        //如果到达了叶节点,可以往result里加入一个结果 
        if (!root->left && !root->right) res.push_back(path); 
        //递归      
        else backtrack(root->left), backtrack(root->right);  
        //回溯      
        path.erase(path.begin() + len, path.end());     
    }

404. 左叶子之和 简单

计算给定二叉树的所有左叶子之和。

class Solution {
public:
    int sumOfLeftLeaves(TreeNode* root) {
        int sum(0);
        //如果是 null的根节点 或 叶节点 的下一轮
        if(!root) return 0;
        //在叶节点的上一层判断:如果 有左结点 且 左结点是叶节点
        if(root->left && !root->left->left &&!root->left->right) sum += root->left->val;
        //加上左子树的值
        if(root->left) sum += sumOfLeftLeaves(root->left);
        //加上右子树的值
        if(root->right) sum += sumOfLeftLeaves(root->right);
        return sum;
    }
};

437. 路径总和 III

找出路径和等于给定数值的路径总数。

class Solution {
public:
    int pathSum(TreeNode* root, int sum) {
        if(!root) return 0; 
        int count(0);
        int add(0);
        queue<TreeNode*> que;
        que.push(root);
        //层序遍历每一个结点
        while(!que.empty()){
            TreeNode* node = que.front();
            //找 当前结点 有多少个路径
            count += oneNodePathSum(node,sum,add);
            que.pop();
            if(node->left) que.push(node->left);
            if(node->right) que.push(node->right);
        }
        return count;
    }
private:
    //int add = 0;
    //int count = 0;
    int oneNodePathSum(TreeNode* root, int sum, int add){//add必须采用参数传递的方式
        if(!root) return 0;
        //count可以在这里定义,因为它可以通过return传递
        int count(0);
        //int add(0); 注意,绝对不可以在这里定义add,否则每次回溯都会把add清0!!
        //add增加当前的值
        add += root->val;
        //记录递归前状态
        int temp = add;
        //如果某一条路径等于sum了,count++,不能return,因为下面可能有负数的结点,可能还有路径
        if(add==sum) ++count;
        //找左子树,不能剪枝,因为可能有负数的结点
        if(root->left){
            count += oneNodePathSum(root->left, sum,add);
            add = temp;//回溯
        }
        ////找右子树,不能剪枝,因为可能有负数的结点
        if(root->right){
            count += oneNodePathSum(root->right, sum,add);
            add = temp;//回溯
        }
        return count;
    }
};

112和257的结合。采用层序遍历每一个结点,对于每一个结点,都采用回溯的方式看看它有几条满足条件的路径。注意,这个add和257题中的vector result一样,可以定义为全局变量,也可以定义在main中,但是必须采用参数传递的方式,否则一直会不变。

现在总结257和437关于回溯的规律:

  1. 判断!root,极限停止条件;
  2. 判断满足条件时的操作;
  3. 记录回溯前状态
  4. 对左子树进行递归和回溯
  5. 对右子树进行递归和回溯

评论区看到另一种做法,就是递归每一个结点,从这个结点往上找,因为从每一个结点往上找的路径是唯一的,记录从这个结点到根节点能有几条路径满足条件;这个思路和那个动态规划的120题很像;

class Solution {
    public int pathSum(TreeNode root, int sum) {
        return helper(root, sum, new int[1000], 0); //0表示根
    }
    //array数组存储某一次递归时所遍历结点的结果值,p表示当前节点的位置
    public int helper(TreeNode root, int sum, int[] array, int p){
        if(root == null)    return 0;
        array[p] = root.val;
        int temp = 0;
        int n = 0;
        for(int i=p; i>=0; i--){
            temp += array[i];
            if(temp == sum) n ++;
        }
        int left = helper(root.left, sum, array, p+1);
        int right = helper(root.right, sum, array, p+1);
        return n+left+right;
    }
}

每次递归都新建一个数组,记录从根节点到这个结点的所有结点的val;相同路径上数组延续根节点的;不同路径的数组是不一样的。

501. 二叉搜索树中的众数 简单

class Solution {
public:
    vector<int> findMode(TreeNode* root) {
        vector<int> result;
        int max(0);
        unordered_map<int,int> mp;
        DFS(root,mp,max);
        for(auto it=mp.begin();it!=mp.end();it++){ <-map中根据val找key的方法
            if((*it).second==max) result.emplace_back((*it).first);
        }
        return result;
    }
private:
    void DFS(TreeNode* root,unordered_map<int,int>& mp,int& max){
        if(!root) return;
        mp[root->val]++;
        max = (max>mp[root->val])?max:mp[root->val];
        if(root->left) DFS(root->left,mp,max);
        if(root->right) DFS(root->right,mp,max);
        return;
    }
};

把它当成一般的树做的。构造一个map,存放着不同val的频数,选取最大的放入vector。

530.783. 二叉搜索树的最小绝对差 简单

给定一个所有节点为非负值的二叉搜索树,求树中任意两节点的差的绝对值的最小值。

class Solution {
public:
    int getMinimumDifference(TreeNode* root) {
        //int类型4个字节,32位,范围-2^31+1~2^31-1
        int mini(1<<31-1);
        int last = -1;  //注意这个flag的玩法
        DFS(root,mini,last);
        return mini;
    }
private:
    void DFS(TreeNode* root, int& mini,int& last){
        if(!root) return;
        //遍历左子树
        DFS(root->left,mini,last);
        //用当前值减去上一个数
        if(last != -1) mini = min(mini,root->val - last);
        //这个数变成上一个数
        last = root->val;  //注意这个错位的玩法
        //遍历右子树
        DFS(root->right,mini,last);
        return;
    }
};

注意,看到二叉搜索树就中序遍历!!
中序遍历的特点是先一口气跑到左子树的最下面,再依次返回来;
右子树是从上慢慢下去。
为什么第二次做就不会了???

538. 把二叉搜索树转换为累加树 简单

给定一个二叉搜索树(Binary Search Tree),把它转换成为累加树(Greater Tree),使得每个节点的值是原来的节点值加上所有大于它的节点值之和。

输入: 二叉搜索树:
5
/
2 13

输出: 转换为累加树:
18
/
20 13

class Solution {
    int add = 0;
public:
    TreeNode* convertBST(TreeNode* root) {
        if(!root) return nullptr;
        convertBST(root->right);
        root->val += add;
        add = root->val;
        convertBST(root->left);
        return root;
    }
};

这个是中序遍历的变种。

938.二叉搜索树的范围和 简单

给定二叉搜索树的根结点 root,返回 L 和 R(含)之间的所有结点的值的和。

class Solution {
public:
    int rangeSumBST(TreeNode* root, int L, int R) {
        int sum = 0;
        int last = -1;
        DFS(root, sum, L, R);
        return sum;       
    }
    void DFS(TreeNode* root, int& sum,const int L, const int R){
        if(root==nullptr) return;
        //左子树
        if(root->left) DFS(root->left,sum,L,R);
        //如果当前结点的值在L-R之间,就相加
        if(root->val>=L && root->val<=R)sum += root->val;
        //右子树
        if(root->right) DFS(root->right,sum,L,R);      
    }
};

核心:if(root->val>=L && root->val<=R)sum += root->val;

543. 二叉树的直径 简单

跟最大深度相关
给定一棵二叉树,你需要计算它的直径长度。一棵二叉树的直径长度是任意两个结点路径长度中的最大值。这条路径可能穿过根结点。
错误解答:
最大直径是左子树和右子树的最大深度之和,但是万一最大直径没有经过根节点呢?所以说对于树中的每一个结点,都要把它视为根节点,然后比较所有结点的左子树和右子树的最大深度之和,取其中的最大值。

class Solution {
public:
    int diameterOfBinaryTree(TreeNode* root) {
        if(!root) return 0;
        int l = 0; int r = 0;
        if(root->left) l = maxdepth(root->left);
        if(root->right) r = maxdepth(root->right);
        return l+r;
    }
    int maxdepth(TreeNode* root){
        if(!root) return 0;
        return max(maxdepth(root->left),maxdepth(root->right))+1;
    }
};

更改:

class Solution {
    int diameterOfBinaryTree(TreeNode* root) {
        if(!root) return 0;
        int maxi = 0;
        //temp没有作用,只是接一下
        int temp = maxdepth(root,maxi);
        //maxi是通过参数引用实现值的修改
        return maxi;
    }
    int maxdepth(TreeNode* root, int& maxi){
        if(!root) return 0;
        //获取左子树的最大深度
        int l = maxdepth(root->left,maxi);
        //获取右子树的最大深度
        int r = maxdepth(root->right,maxi);
        //获取以所有结点作为根节点时,各自的直径中的最大值
        maxi = max(maxi, l+r);
        //这个树的最大深度
        return max(l,r)+1;
    }
};

563. 二叉树的坡度 简单

给定一个二叉树,计算整个树的坡度。一个树的节点的坡度定义即为,该节点左子树的结点之和和右子树结点之和的差的绝对值。空结点的的坡度是0。整个树的坡度就是其所有节点的坡度之和。

class Solution {
public:
    int findTilt(TreeNode* root) {
        if(!root) return 0;
        //树的坡度 = 左子树的坡度 + 右子树的坡度 + 结点的坡度
        return (findTilt(root->left) + findTilt(root->right) + oneTilt(root));
    }
private:
    int oneTilt(TreeNode* root){
        if(!root) return 0;
        //结点的坡度 = abs(左子树和 - 右子树和)
        return abs(sum(root->left) - sum(root->right));
    }
    int sum(TreeNode *root){
        if(!root) return 0;
        //树的和 = 左子树的和 + 右子树的和 + 结点的val
        return(root->val + sum(root->left) + sum(root->right));
    }
};

效率提升版:和543题采取了相同的策略

class Solution {
public:
    int findTilt(TreeNode* root) {
        if(!root) return 0;
        int tile = 0;
        int summ = sum(root,tile);
        return tile;
    }
private:
    int sum(TreeNode *root, int& tile){
        if(!root) return 0;
        int l = sum(root->left,tile);
        int r = sum(root->right,tile);
        //坡度等于之前的坡度的累积加上自己的坡度
        tile += abs(l-r);
        //树的和 = 左子树的和 + 右子树的和 + 结点的val
        return(root->val + l + r);
    }
};

核心:tile += abs(l-r);

572.另一个树的子树 简单

给定两个非空二叉树 s 和 t,检验 s 中是否包含和 t 具有相同结构和节点值的子树。s 的一个子树包括 s 的一个节点和这个节点的所有子孙。s 也可以看做它自身的一棵子树。

class Solution {
public:
    bool isSubtree(TreeNode* s, TreeNode* t) {
        if(!s && !t) return true;
        if(t && !s) return false;
        //if(s && !t) return false;
        //如果t是s左子树下面,或者s右子树下面或者t=s,那么true
        return isSubtree(s->left,t) || isSubtree(s->right,t) || isSame(s,t);
    }
private:
    bool isSame(TreeNode* s, TreeNode* t){
        //以下3个判断目的是确保对 叶节点下一层 的判断
        if(!s && !t) return true;
        if(!s && t) return false;
        //if(s && !t) return false;
        //如果两棵树都有,且左右子树一样,当前结点一样,则true
        return s&&t && isSame(s->left,t->left) && isSame(s->right,t->right) && (s->val == t->val);
    }
};

思路很简答,而且是100题的拓展。但是要注意if的判断。if除了判断根节点,更重要的是判断叶节点后面的内容,这是迭代到头的依据。

你可能感兴趣的:(Leetcode)