二叉树和递归面试总结

1. 二叉树的遍历

2.1 Leetcode 144:Binary Tree Preorder Traversal

求一个二叉树的前序遍历。
例如:
在这里插入图片描述
解法一(递归写法):先处理当前结点,然后在递归处理左子树和右子树。

class Solution {
private:
    vector<int> res; //必须声明为类成员变量,如果在函数里面声明,则结果会报错,不知道原因。
public:
	vector<int> preorderTraversal(TreeNode* root) {
        if(root == NULL)
            return res;
        res.push_back(root->val);
        preorderTraversal(root->left);
        preorderTraversal(root->right);
        return res;
	}
};

另一种写法(标准写法):

class Solution {
public:
	vector<int> preorderTraversal(TreeNode* root) {
        vector<int> res;
        preorderTraversal(root, res);
        return res;
	}
private:
    void preorderTraversal(TreeNode* node, vector<int>& res) {
        if(node == NULL)
            return;
        res.push_back(node->val);
        preorderTraversal(node->left, res);
        preorderTraversal(node->right, res);
	}
};

解法二(非递归写法):前序遍历是根左右的顺序,则入栈的顺序是右左根

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
struct Command {
	string s;
	TreeNode* node;
	Command(string s1, TreeNode* node1) : s(s1), node(node1){}
};
class Solution {
public:
	vector<int> preorderTraversal(TreeNode* root) {
		vector<int> res;
		if (root == NULL)
			return res;
		stack<Command> stack;
		stack.push(Command("go", root));
		while (!stack.empty()){
			Command command = stack.top();
			stack.pop();
			if (command.s == "print")
				res.push_back(command.node->val);
			else{
				assert(command.s == "go");
				if (command.node->right)
					stack.push(Command("go", command.node->right));
				if (command.node->left)
					stack.push(Command("go", command.node->left));
				stack.push(Command("print", command.node));
			}
		}
		return res;
	}
};
2.2 Leetcode 94:Binary Tree Inorder Traversal

求一个二叉树的中序遍历。
例如:
在这里插入图片描述
解法一(递归写法):先递归处理左子树,然后在处理当前节点,最后递归处理右子树。

class Solution {
public:
	vector<int> inorderTraversal(TreeNode* root) {
        vector<int> res;
        inorderTraversal(root, res);
        return res;
	}
private:
    void inorderTraversal(TreeNode* node, vector<int>& res) {
        if(node == NULL)
            return;
        inorderTraversal(node->left, res);
        res.push_back(node->val);
        inorderTraversal(node->right, res);
	}
};

解法二(非递归写法):中序遍历是左根右的顺序。则入栈的顺序是右根左

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
struct Command{
	string s;
	TreeNode* node;
	Command(string s1, TreeNode* node1) : s(s1), node(node1){}
};
class Solution{
public:
	vector<int> inorderTraversal(TreeNode* root){
		vector<int> res;
		if (root == NULL)
			return res;
		stack<Command> stack;
		stack.push(Command("go", root));
		while (!stack.empty()){
			Command command = stack.top();
			stack.pop();
			if (command.s == "print")
				res.push_back(command.node->val);
			else{
				assert(command.s == "go");
				if (command.node->right)
					stack.push(Command("go", command.node->right));
				stack.push(Command("print", command.node));
				if (command.node->left)
					stack.push(Command("go", command.node->left));
			}
		}
		return res;
	}
};
2.3 Leetcode 145:Binary Tree Postorder Traversal

求一个二叉树的后序遍历。
例如:
在这里插入图片描述
解法一(递归写法):先递归处理左子树,然后在递归处理右子树,最后处理当前结点。

class Solution {
public:
	vector<int> postorderTraversal(TreeNode* root) {
        vector<int> res;
        postorderTraversal(root, res);
        return res;
	}
private:
    void postorderTraversal(TreeNode* node, vector<int>& res) {
        if(node == NULL)
            return;
        postorderTraversal(node->left, res);
        postorderTraversal(node->right, res);
        res.push_back(node->val);
	}
};

解法二(非递归写法):后序遍历是左右根的顺序。则入栈的顺序是根右左

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
struct Command{
	string s;
	TreeNode* node;
	Command(string s1, TreeNode* node1) : s(s1), node(node1){}
};
class Solution{
public:
	vector<int> inorderTraversal(TreeNode* root){
		vector<int> res;
		if (root == NULL)
			return res;
		stack<Command> stack;
		stack.push(Command("go", root));
		while (!stack.empty()){
			Command command = stack.top();
			stack.pop();
			if (command.s == "print")
				res.push_back(command.node->val);
			else{
				assert(command.s == "go");
				stack.push(Command("print", command.node));
				if (command.node->right)
					stack.push(Command("go", command.node->right));
				if (command.node->left)
					stack.push(Command("go", command.node->left));
			}
		}
		return res;
	}
};
2.4 Leetcode 102:Binary Tree Level Order Traversal

求一个二叉树的层序遍历。
例如:
在这里插入图片描述
解法一(递归):将当前节点,当前所在的level以及结果数组传递给递归函数。在递归函数中,取出节点的值,添加到level参数对应结果数组元素中。

class Solution {
public:
    vector<vector<int>> levelOrder(TreeNode* root) {
        vector<vector<int>> res;
        levelOrder(root, 0, res);
        return res;
    }
private:
    void levelOrder(TreeNode* root, int level, vector<vector<int>>& res) {
        if (root == NULL) 
        	return;
        if (res.size() == level) 
        	res.resize(level + 1);
        res[level].push_back(root->val);
        levelOrder(root->left, level + 1, res);
        levelOrder(root->right, level + 1, res);
    }
};

解法二(非递归):首先将根结点以及所在的层数(第0层)入队,然后遍历队列,若队列不为空,取出队首位置并将队首结点的val值入栈;然后判断其左右孩子是否存在,若存在,则将该孩子结点以及所在层数入队。

class Solution{
public:
	vector<vector<int>> levelOrder(TreeNode* root){
		vector<vector<int>> res;
		if (root == NULL)
			return res;
		queue<pair<TreeNode*, int>> q;
		q.push(make_pair(root, 0));
		while (!q.empty()){
			TreeNode* node = q.front().first;
			int level = q.front().second;
			q.pop();
			if (level == res.size())
				res.resize(level + 1);
			res[level].push_back(node->val);
			if (node->left)
				q.push(make_pair(node->left, level + 1));
			if (node->right)
				q.push(make_pair(node->right, level + 1));
		}
		return res;
	}
};
2.5 Leetcode 103. Binary Tree Zigzag Level Order Traversal

对一个二叉树的层序遍历,按照“之”字形的顺序返回所有结点。
例如:
在这里插入图片描述
解法一:先按照层序遍历算法将所有结点push进一个二维的vector中,然后在遍历一次该vector,将索引为奇数的进性reverse操作。

class Solution{
public:
	vector<vector<int>> zigzagLevelOrder(TreeNode* root){
		vector<vector<int>> res;
		if (root == NULL)
			return res;
		queue<pair<TreeNode*, int>> q;
		q.push(make_pair(root, 0));
		while (!q.empty()){
			TreeNode* node = q.front().first;
			int level = q.front().second;
			q.pop();
			if (level == res.size())
				res.push_back(vector<int>());
			res[level].push_back(node->val);
			if (node->left)
				q.push(make_pair(node->left, level + 1));
			if (node->right)
				q.push(make_pair(node->right, level + 1));
		}
		// reverse
		for (int i = 1; i < res.size(); i += 2)
			res[i] = vector<int>(res[i].rbegin(), res[i].rend());
		return res;
	}
};

解法二:设立两个栈,偶数行的栈按照从左到右的顺序保存结点,奇数行的栈从右到左保存。

class Solution{
public:
	vector<vector<int>> zigzagLevelOrder(TreeNode* root){
		vector<vector<int>> res;
        if(root == nullptr)
            return res;
        stack<TreeNode*> s[2];
        int current = 0, next = 1;
        s[current].push(root);
        vector<int> tmp;
        while(!s[0].empty() || !s[1].empty()){
            TreeNode* node = s[current].top();
            s[current].pop();
            tmp.push_back(node->val);
            if(current == 0){
                if(node->left != nullptr)
                    s[next].push(node->left);
                if(node->right != nullptr)
                    s[next].push(node->right);
            }
            else{
                if(node->right != nullptr)
                    s[next].push(node->right);
                if(node->left != nullptr)
                    s[next].push(node->left);
            }
            if(s[current].empty()){
                res.push_back(tmp);
                tmp.clear();
                current = 1 - current;
                next = 1 - next;
            }
        }
        return res;
	}
};
2.6 Leetcode 199. Binary Tree Right Side View

想象你站在一颗二叉树的右侧,返回所有你能看见的结点。
例如:
在这里插入图片描述
解法一(非递归):先按照层序遍历算法将所有结点push进一个二维的vector中,然后在遍历一次该vector,将每个索引所对应 的一维vector中最后一个元素压入到resultVector中。

class Solution{
public:
	vector<int> rightSideView(TreeNode* root){
		vector<vector<int>> record;
		vector<int> res;
		if (root == NULL)
			return res;
		queue<pair<TreeNode*, int>> q;
		q.push(make_pair(root, 0));
		while (!q.empty()){
			TreeNode* node = q.front().first;
			int level = q.front().second;
			q.pop();
			if (level == record.size())
				record.push_back(vector<int>());
			record[level].push_back(node->val);
			if (node->left)
				q.push(make_pair(node->left, level + 1));
			if (node->right)
				q.push(make_pair(node->right, level + 1));
		}
		// push操作
		for (int i = 0; i < record.size(); i++)
			res.push_back(record[i][record[i].size() - 1]);			
		return res;
	}
};

解法二:按照层序遍历把当前某一层的所有结点push到队列里,在遍历下一层结点时,pop掉队列里这层所有node,同时记录最右边的值。

class Solution{
public:
	vector<int> rightSideView(TreeNode* root){
        vector<int> res;
		if(root == nullptr)
            return res;
        queue<TreeNode*> q;
        q.push(root);
        while(!q.empty()){
            int last_size = q.size();
            int val = 0;
            for(int i = 0; i < last_size; i++){
                TreeNode* node = q.front();
                q.pop();
                val = node->val;
                if(node->left)
                    q.push(node->left);
                if(node->right)
                    q.push(node->right);
            }
            res.push_back(val);
        }
        return res;
	}
};
2.7 Leetcode 104. Maximum Depth of Binary Tree

求一颗二叉树的最高深度。
例如:
在这里插入图片描述
解法(递归): 分别求出以root为根的左右子树的最高深度,则当前结点root的高度是左右子树最大高度+1。

class Solution{
public:
	int maxDepth(TreeNode* root) {
		if (root == NULL)
			return 0;
		return max(maxDepth(root->left), maxDepth(root->right)) + 1;
	}
};
2.8 Leetcode 111. Minimum Depth of Binary Tree

求一颗二叉树的最低深度。
例如:
在这里插入图片描述
解法(递归,注意与求最大深度的不同): 分别求出以root为根的左右子树的最高深度,若当前结点root左右子树有一棵子树为空,则高度应该是不为空的那棵子树高度+1;否则高度是左右子树最小高度+1。

class Solution{
public:
	int minDepth(TreeNode* root){
		if (root == NULL)
			return 0;
		int left = minDepth(root->left);
		int right = minDepth(root->right);
		return left == 0 || right == 0 ? left + right + 1 : min(left, right) + 1;
	}
};
2.9 Leetcode 226. Invert Binary Tree

反转一棵二叉树。
例如:
在这里插入图片描述
解法(递归):遍历树(随便怎么遍历),然后将左右子树交换位置。

class Solution{
public:
	TreeNode* invertTree(TreeNode* root){
		if (root == NULL)
			return NULL;
		swap(root->left, root->right);
		invertTree(root->left);
		invertTree(root->right);
		return root;
	}
};
2.10 Leetcode 110. Balanced Binary Tree

判断一棵二叉树是否为平衡二叉树,即每一个结点的左右子树高度差不超过1。
解法一: 先计算当前节点左右子树的高度差,如果超过1,则返回false;否则判断该结点的左右子树是否为平衡二叉树。

class Solution{
public:
	bool isBalanced(TreeNode* root){
		if (root == NULL)
			return true;
		int diff = depth(root->left) - depth(root->right);
		bool res = abs(diff) > 1 ? false : true;
		return res && isBalanced(root->left) && isBalanced(root->right);
	}
private:
	int depth(TreeNode* node){
		if (node == NULL)
			return 0;
		return max(depth(node->left), depth(node->right)) + 1;
	}
};

解法二: 使用后序遍历遍历二叉树的每个结点,那么在遍历到每个结点之前就已经遍历了它的左右子树。只要在遍历每个结点的同时记录该结点的深度,我们可以一边判断每个结点是不是平衡的。

class Solution{
public:
	bool isBalanced(TreeNode* root){
        int depth = 0;
		return isBalancedCore(root, depth);
	}
private:
    bool isBalancedCore(TreeNode* node, int& depth){
        if(node == nullptr){
            depth = 0;
            return true;
        }
        int left, right;
        if(isBalancedCore(node->left, left) && isBalancedCore(node->right, right)){
            int diff = left - right;
            if(abs(diff) <= 1){
                depth = max(left, right) + 1;
                return true;
            }
        }
        return false;
    }
};
2.11 Leetcode 257. Binary Tree Paths

给定一个二叉树,返回所有表示从根结点到叶子结点路径的字符串。
例如:
在这里插入图片描述
解法(递归):分别求出该结点左右子树的路径,则该结点的路径为"node->val"加上左右子树的路径。

class Solution {
public:
	vector<string> binaryTreePaths(TreeNode* root){
		vector<string> res;
		if (root == NULL)
			return res;
		if (root->left == NULL && root->right == NULL){
			res.push_back(to_string(root->val));
			return res;
		}
		auto leftS = binaryTreePaths(root->left);
		for (int i = 0; i < leftS.size(); i++)
			res.push_back(to_string(root->val) + "->" + leftS[i]);
		auto rightS = binaryTreePaths(root->right);
		for (int i = 0; i < rightS.size(); i++)
			res.push_back(to_string(root->val) + "->" + rightS[i]);
		return res;
	}
};
2.12 Leetcode 437. Path Sum III

给出一棵二叉树以及一个数字sum,判断这棵二叉树上存在多少条路径,其路径上所有结点和为sum。

  • 其中路径不一定要起始于根结点,终止于叶子结点;
  • 路径可以从任意结点开始,但是只能向下走

例如:
在这里插入图片描述
解法(递归):注意分两种情况:node在不在该路径中。在的话调用findPath。

class Solution{
public:
	//在以root为根结点的二叉树中,寻找和为sum的路径,返回这样的路径个数
	int pathSum(TreeNode* root, int sum) {
		if (root == NULL)
			return 0;
		int res = findPath(root, sum);
		res += pathSum(root->left, sum);
		res += pathSum(root->right, sum);
		return res;
	}
private:
	//在以node为根结点的二叉树中,寻找包含node且和为sum的路径,返回这样的路径个数
	int findPath(TreeNode* node, int sum){
		int pathNum = 0;
		if (node == NULL)
			return pathNum;
		if (node->val == sum) //不能直接return pathNum,因为在这个题中存在负数,有可能在下面的路径加减一个相同的数其sum不变 
			pathNum += 1;
		pathNum += findPath(node->left, sum - node->val);
		pathNum += findPath(node->right, sum - node->val);
		return pathNum;
	}
};
2.13 Leetcode 235. Lowest Common Ancestor of a Binary Search Tree

给出一棵二分搜索树和两个结点,寻找这两个结点的最近公共祖先。
例如:
在这里插入图片描述
解法(递归):注意分两种情况:若p,q在同一侧,则继续递归;如果在不同侧,那么又有三种情况:node为p,q的最近公共祖先,p为p,q的最近公共祖先和q为p,q的最近公共祖先。不过这三种情况可以归为一个,其最近公共祖先就是node。

class Solution {
public:
	TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q){
		assert(p && q);
		if (root == NULL)
			return NULL;
		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);
		return root;
	}
};
2.14 Leetcode 236. Lowest Common Ancestor of a Binary Tree

给出一棵二叉树和两个结点,寻找这两个结点的最近公共祖先。
例如:
在这里插入图片描述
解法(递归):如下图所示。
在这里插入图片描述

class Solution {
public:
	TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q){
		if (root == NULL || root == p || root == q)
			return root;
		TreeNode* left = lowestCommonAncestor(root->left, p, q);
        TreeNode* right = lowestCommonAncestor(root->right, p, q);
        if(left == NULL)
            return right;
        if(right == NULL)
            return left;
        return root;
	}
};
2.15 Leetcode 230. Kth Smallest Element in a BST

给出一棵二分搜索树,寻找其第k小元素。
例如:
在这里插入图片描述
解法一:将二分搜索树中序遍历得到一个有序数组,然后返回第k个元素。

class Solution{
public:
	int kthSmallest(TreeNode* root, int k){
		if (root == NULL)
			return 0;
		vector<int> records;
		inOrder(root, records);
		return records[k - 1];
	}
private:
	void inOrder(TreeNode* root, vector<int>& records){
		if (root == NULL)
			return;
		inOrder(root->left, records);
		records.p_back(root->val);
		inOrder(root->right, records);
	}
};

解法二:直接将二分搜索树中序遍历得到第k个元素。

class Solution{
public:
	int kthSmallest(TreeNode* root, int k){
		if (root == NULL || k < 1)
			return 0;
        return inorder(root, k)->val;
    }
private:
    TreeNode* inorder(TreeNode* node, int& k){
        TreeNode* target = nullptr;
        if(node->left != nullptr)
            target = inorder(node->left, k);
        if(target == nullptr){
            if(k == 1)
                target = node;
            k--;
        }
        if(target == nullptr && node->right != nullptr)
            target = inorder(node->right, k);
        return target;
    }
};
2.16 Leetcode 543. Diameter of Binary Tree

给出一棵二叉树,求其直径。
在这里插入图片描述
解法一:以根结点为root的二叉树直径为:左子树的直径右子树的直径左右子树最大深度之和这三种情况的最大值。

class Solution {
public:
    int diameterOfBinaryTree(TreeNode* root){
        if(root == NULL)
            return 0;
        int depth_sum = maxDepth(root->left) + maxDepth(root->right);
        int left_diameter = diameterOfBinaryTree(root->left);
        int right_diameter = diameterOfBinaryTree(root->right);
        return max(depth_sum, max(left_diameter, right_diameter));
    }
  private:
  	int maxDepth(TreeNode* node){
  		if(node == NULL)
  			return 0;
  		return max(maxDepth(node->left), maxDepth(node->right)) + 1;
  	}  
};

解法二:以根结点为root的二叉树直径为每个结点左右子树深度之和的最大值

class Solution {
public:
    int diameterOfBinaryTree(TreeNode* root){
        if(root == NULL)
            return 0;
        int res = 0;
        depth(root, res);
        return res;
    }
  private:
  	int depth(TreeNode* node, int& res){
  		if(node == NULL)
  			return 0;
  		int left_depth = depth(node->left, res);
  		int right_depth = depth(node->right, res);
  		res = max(res, left_depth + right_depth);
  		return max(left_depth, right_depth) + 1;
  	}
};
2.17 Leetcode 958. Check Completeness of a Binary Tree

判断一棵二叉树是否为完全二叉树。
在这里插入图片描述
解法一: 层次遍历二叉树,一直找到某个空节点。若之后的结点都是空节点,那么该二叉树是完全二叉树,一旦出现某个结点不是空节点,则就不是完全二叉树。

class Solution{
public:
	bool isCompleteTree(TreeNode* root){
		if(root == nullptr)
			return true;
		queue<TreeNode*> q;
		q.push(root);
		bool has_null = false;
		while(!q.empty()){
			TreeNode* node = q.front();
			q.pop();
			if(node != nullptr){
				if(has_null)
					return false;
				q.push(node ->left);
				q.push(node->right);
			}
			else
				has_null = true;
		}
		return true;
	}
};

解法二: 层次遍历二叉树,位置id的结点其左孩子的id为2id,右孩子为2id+1。如果该二叉树是完全二叉树,那么最后一个结点的id应该和结点个数相等。

class Solution{
public:
	bool isCompleteTree(TreeNode* root){
		if(root == nullptr)
			return true;
		//注意,这里一定是unsigned int,否则会报整型溢出
		vector<pair<TreeNode*, unsigned int>> vec; 
		vec.push_back(make_pair(root, 1))
		for(int i = 0; i < vec.size(); i++){
			TreeNode* node = vec[i].first;
			unsigned int id = vec[i].second;
			if(node != nullptr){
				vec.push_back(make_pair(node->left, 2*id));
				vec.push_back(make_pair(node->right, 2*id+1));
			}
		}
		return vec.size() == vec[vec.size()-1].second;
	}
};
2.17 Leetcode 958. Validate Binary Search Tree

判断一棵二叉树是否为二叉搜索树。
解法一(递归):利用中序遍历判断。

class Solution{
public:
	bool isValidBST(TreeNode* root){
		TreeNode* prev = nullptr;
		return check(root, prev);
	}
private:
	//注意prev传的是引用
	bool check(TreeNode* node, TreeNode* &prev){
		if(node == nullptr)
			return true;
		if(!check(node->left, prev))
			return false;
		if(prev && prev->val >= node->val)
			return false;
		prev = node;
		return check(node->right, prev);
	}
};

解法二(非递归):利用中序遍历判断。

class Solution{
public:
	bool isValidBST(TreeNode* root){
		if(root == nullptr)
            return true;
        stack<TreeNode*> s;
        TreeNode* node = root;
        TreeNode* pre_node = nullptr;
        while(node || !s.empty()){
            while(node){
                s.push(node);
                node = node->left;
            }
            TreeNode* cur_node = s.top();
            s.pop();
            if(pre_node && pre_node->val >= cur_node->val)
                return false;
            pre_node = cur_node;
            node = cur_node->right;
        }
        return true;
	}
};
2.17 Leetcode 513. Find Bottom Left Tree Value

求一个二叉树的最后一行的最左边结点。
在这里插入图片描述
解法:对二叉树层序遍历,先保存当前结点的val值。然后把右孩子的结点push到队列里,再把左孩子的结点push到队列里。

class Solution {
public:
    int findBottomLeftValue(TreeNode* root) {
        if(root == nullptr)
            return 0;
        queue<TreeNode*> q;
        q.push(root);
        int res = 0;
        while(!q.empty()){
            TreeNode* node = q.front();
            q.pop();
            res = node->val;
            if(node->right) //先右边
                q.push(node->right);
            if(node->left) //后左边
                q.push(node->left);
        }
        return res;
    }
};
2.17 Leetcode 515. Find Bottom Left Tree Value

求一个二叉树的每一行的最大值。
在这里插入图片描述
解法:层序遍历。

class Solution {
public:
    vector<int> largestValues(TreeNode* root){
        vector<int> res;
        if(root == nullptr)
            return res;
        queue<TreeNode*> q;
        q.push(root);
        while(!q.empty()){
            int last_size = q.size();
            int max_val = INT_MIN;
            for(int i = 0; i < last_size; i++){
                TreeNode* node = q.front();
                q.pop();
                max_val = max_val < node->val ? node->val : max_val;
                if(node->left)
                    q.push(node->left);
                if(node->right)
                    q.push(node->right);
            }
            res.push_back(max_val);
        }
        return res;
    } 
};
2.18 Leetcode 96. Unique Binary Search Trees

给定一个数字n,求它构成所有不同二叉搜索树的个数。
在这里插入图片描述
解法(动态规划):n == 0 时,空树的个数必然为1,因此dp[0] = 1,n == 1 时,只有1这个根节点,数量也为1,因此dp[1] = 1。假设n个节点存在二叉排序树的个数是dp[n],令f(i)为以i为根的二叉搜索树的个数,则dp[n] = f(1) + f(2) + f(3) + f(4) + … + f(n),当i为根节点时,其左子树节点个数为i-1个,右子树节点为n-i,则f(i) = dp[i-1]dp[n-i],综合两个公式可以得到卡特兰数公式:dp[n] = dp[0]*dp[n-1]+dp[1]dp[n-2]+…+dp[n-1]*dp[0]

class Solution {
public:
    int numTrees(int n) {
        if(n < 0)
            return 0;
        if(n == 0 || n == 1)
            return 1;
        vector<int> dp(n + 1, 0);
        dp[0] = 1;
        dp[1] = 1;
        for(int i = 2; i <= n; i++)
            for(int j = 0; j < i; j++)
                dp[i] += dp[j] * dp[i - j - 1];
        return dp[n];
    }
};
2.19 重建二叉树

输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。

class Solution {
public:
    TreeNode* reConstructBinaryTree(vector<int> pre,vector<int> vin) {
        if(pre.empty() || vin.empty() || pre.size() != vin.size())
            return nullptr;
        return construct(pre, vin, 0, pre.size() - 1, 0, vin.size() - 1);
    }
private:
    TreeNode* construct(vector<int>& pre, vector<int>& vin, int pre_start, int pre_end, int in_start, int in_end){
        int root_value = pre[pre_start];
        TreeNode* root = new TreeNode(root_value);
        if(pre_start == pre_end && in_start == in_end && pre[pre_start] == vin[in_start])
            return root;
        int root_idx_of_in = 0;
        while(vin[root_idx_of_in] != root_value)
            root_idx_of_in++;
        int left_len = root_idx_of_in - in_start;
        int pre_left_end = pre_start + left_len;
        if(left_len > 0)
            root->left = construct(pre, vin, pre_start + 1, pre_left_end, in_start, root_idx_of_in - 1);
        if(left_len < in_end - in_start)
            root->right = construct(pre, vin, pre_left_end + 1, pre_end, root_idx_of_in + 1, in_end);
        return root;
    }
};
2.20 树的子结构

输入两棵二叉树A,B,判断B是不是A的子结构。(ps:我们约定空树不是任意一个树的子结构)。

class Solution {
public:
    bool HasSubtree(TreeNode* pRoot1, TreeNode* pRoot2){
        bool res = false;
        if(pRoot1 != nullptr && pRoot2 != nullptr){
            if(pRoot1->val == pRoot2->val)
                res = DoesTree1HaveTree2(pRoot1, pRoot2);
            if(!res)
                res = HasSubtree(pRoot1->left, pRoot2) || HasSubtree(pRoot1->right, pRoot2);
        }
        return res;
    }
private:
    bool DoesTree1HaveTree2(TreeNode* pRoot1, TreeNode* pRoot2){  
        if(pRoot2 == nullptr) //跟顺序有关系,必须得先判断pRoot2,然后在判断pRoot1
            return true;
        if(pRoot1 == nullptr)
            return false;
        if(pRoot1->val != pRoot2->val)
            return false;
        return DoesTree1HaveTree2(pRoot1->left, pRoot2->left) && DoesTree1HaveTree2(pRoot1->right, pRoot2->right);
    }
};
2.21 二叉树和为某一值的路径

输入一颗二叉树的根节点和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。(注意: 在返回值的list中,数组长度大的数组靠前)。

class Solution {
public:
    vector<vector<int> > FindPath(TreeNode* root,int expectNumber) {
        vector<vector<int>> res;
        if(root == nullptr)
            return res;
        vector<int> path;
        FindPathCore(root, expectNumber, res, path);
        return res;
    }
private:
    void FindPathCore(TreeNode* node, int expectNumber, vector<vector<int>>& res, vector<int>& path) {
        path.push_back(node->val);
        if(node->left == nullptr && node->right == nullptr && expectNumber == node->val)
            res.push_back(path);
        if(node->left != nullptr)
            FindPathCore(node->left, expectNumber - node->val, res, path);
        if(node->right != nullptr)
            FindPathCore(node->right, expectNumber - node->val, res, path);
        path.pop_back();
        return;
    }
};
2.22 二叉树与双向链表

输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。

class Solution {
public:
    TreeNode* Convert(TreeNode* pRootOfTree){
        TreeNode* pLastNodeInList = nullptr;
        convertCore(pRootOfTree, &pLastNodeInList);
        TreeNode* head = pLastNodeInList;
        while(head != nullptr && head->left != nullptr)
            head = head->left;
        return head;
    }
private:
    void convertCore(TreeNode* node, TreeNode** pLastNodeInList)
    {
        if(node == nullptr)
            return;
        TreeNode* cur = node;
        if(cur->left != nullptr)
            convertCore(cur->left, pLastNodeInList);
        cur->left = *pLastNodeInList;
        if(*pLastNodeInList != nullptr)
            (*pLastNodeInList)->right = cur;
        *pLastNodeInList = cur;
        if(cur->right != nullptr)
            convertCore(cur->right, pLastNodeInList);
    }
};
2.23 二叉树的下一个结点

给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。
解法:(1)当前结点有右子树,那么他的下一个结点是右子树的最左结点;(2)当前结点没有右子树:a)如果该结点是父结点的左孩子,那么父结点就是他的下一个结点;b)如果该结点是父结点的右孩子,不断向上找父结点,直至当前结点是其父亲的左孩子位置。如果没有,那么就是尾结点。

class Solution {
public:
    TreeLinkNode* GetNext(TreeLinkNode* pNode){
        if(pNode == nullptr)
            return nullptr;
        if(pNode->right != nullptr){
            pNode = pNode->right;
            while(pNode->left != nullptr)
                pNode = pNode->left;
            return pNode;
        }
        while(pNode->next != nullptr && pNode->next->right == pNode)
            pNode = pNode->next;
        return pNode->next;
    }
};
2.23 对称的二叉树

请实现一个函数,用来判断一颗二叉树是不是对称的。注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的.

class Solution {
public:
    bool isSymmetrical(TreeNode* pRoot){
       return isSymmetricalCore(pRoot, pRoot);
    }
private:
    bool isSymmetricalCore(TreeNode* root1, TreeNode* root2){
        if(root1 == nullptr && root2 == nullptr)
            return true;
        if(root1 == nullptr || root2 == nullptr)
            return false;
        if(root1->val != root2->val)
            return false;
        return isSymmetricalCore(root1->left, root2->right) && isSymmetricalCore(root1->right, root2->left);
    }
};
2.24 序列化二叉树

请实现两个函数,分别用来序列化和反序列化二叉树

二叉树的序列化是指:把一棵二叉树按照某种遍历方式的结果以某种格式保存为字符串,从而使得内存中建立起来的二叉树可以持久保存。序列化可以基于先序、中序、后序、层序的二叉树遍历方式来进行修改,序列化的结果是一个字符串,序列化时通过 某种符号表示空节点(#),以 ! 表示一个结点值的结束(value!)。

二叉树的反序列化是指:根据某种遍历顺序得到的序列化字符串结果str,重构二叉树

class Solution {
public:
    char* Serialize(TreeNode *root) {    
        string str;
        serializeCore(root, str);
        char* ret = new char[str.length() + 1];
        int i;
        for(i = 0; i < str.length(); i++){
            ret[i] = str[i];
        }
        ret[i] = '\0';
        return ret;
    }
    TreeNode* Deserialize(char *str) {
        if(str == nullptr || *str == '\0')
            return nullptr;
        TreeNode* root = deserializeCore(&str);
        return root;
    }
private:
    void serializeCore(TreeNode* root, string& str){
        if(root == nullptr){
            str += '#';
            return;
        }
        str += to_string(root->val);
        str += '!';
        serializeCore(root->left, str);
        serializeCore(root->right, str);
    }
    TreeNode* deserializeCore(char** str){
        if(**str == '#'){
            ++(*str);
            return nullptr;
        }
        int num = 0;
        while(**str != '\0' && **str != '!'){
            num = num * 10 + ((**str) - '0');
            ++(*str);
        }
        TreeNode* root = new TreeNode(num);
        if(**str == '\0')
            return root;
        else
            ++(*str);
        root->left = deserializeCore(str);
        root->right = deserializeCore(str);
        return root;
    }
};     
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值