七、 二叉树学习2(代码随想录学习)

8. 对称二叉树

leetcode链接

思路: 首先想清楚,判断对称二叉树要比较的是哪两个节点,要比较的可不是左右节点!
对于二叉树是否对称,要比较的是根节点的左子树与右子树是不是相互翻转的,理解这一点就知道了其实我们要比较的是两个树(这两个树是根节点的左右子树),所以在递归遍历的过程中,也是要同时遍历两棵树。

递归法: 递归需要比较某层外侧与内侧对应的节点是否相同,首先确定参数是 两个树节点用于相互比较,其次确定终止条件 如果两个节点都为空那么返回true 如果有其中一个节点为空 那么返回false 剩余的情况就是两个节点都不为空,需要比较这两个节点的值以及 这两个节点左右子树是否对称的情况,对应的是左子树的左节点比较右子树的右节点,左子树的右节点比较右子树左节点

class Solution {
public:
	bool compare(TreeNode* left,TreeNode* right) {
		// 判断空结点的跳出循环的条件
		if (left == NULL && right != NULL) return false;
		else if (left != NULL && right == NULL) return false;
		else if (left == NULL && right == NULL) return true;
		else if (left->val != right->val) return false;   // 当对比结点的值不相等时,返回false

		// 剩余左右结点均不为空,且val相等的情况
		// 继续向下递归,判断后续子树是否对称

		// 比较外侧,左结点的左子树和右节点的右子树
		bool outside = compare(left->left, right->right); 
		// 比较里侧,左节点的右子树和右节点的左子树
		bool inside = compare(left->right, right->left);
		// 判断当前结点的情况(左右都对称返回true)
		return outside && inside;

		
	}
	bool isSymmetric(TreeNode* root) {
		if (root == NULL) return true;
		return compare(root->left, root->right);
	}
};

迭代法: 利用队列存储每次要比较的结点,若相等,则将两结点的左右孩子入队,直至遍历完整个二叉树;反之,则直接返回false。

class Solution {
public:
	bool isSymmetric(TreeNode* root) {
		if (root == NULL) return true;
		queue<TreeNode*> que;
		que.push(root->left);
		que.push(root->right);
		while (!que.empty()) {
			TreeNode* cur1 = que.front();
			que.pop();
			TreeNode* cur2 = que.front();
			que.pop();
			// 当一边为空,一边非空时,返回false
			if (cur1 == NULL && cur2 != NULL) return false;
			else if (cur1 != NULL && cur2 == NULL) return false;
			// 当两边均为空时,表示当前子树符合条件,直接对比队中剩下的结点
			else if (cur1 == NULL && cur2 == NULL) continue;
			else if (cur1->val != cur2->val) return false;  // 结点值不相等时,返回false
			
			// 将需要比较的两节点,连续入队
			// 左结点的左孩子和右节点的右孩子
			que.push(cur1->left);
			que.push(cur2->right);
			// 左结点的右孩子和右节点的左孩子
			que.push(cur1->right);
			que.push(cur2->left);
		}
		return true;
	}
};

时间复杂度: O(n)
空间复杂度: O(n)

10. 二叉树的最大深度

leetcode链接

思路: 与层序遍历9相同

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

10. 二叉树的最小深度

leetcode链接

思路: 与层序遍历10一致

class Solution {
public:
	int minDepth(TreeNode* root) {
		int depth = 0;
		queue<TreeNode*> que;
		if (root == NULL) return depth;
		que.push(root);
		while (!que.empty()) {
			int size = que.size();
			depth++;
			for (int i = 0; i < size; i++) {
				TreeNode* cur = que.front();
				que.pop();
				if (cur->left != NULL) que.push(cur->left);
				if (cur->right != NULL) que.push(cur->right);
				// 当左右孩子均为空时,返回当前深度
				if (cur->left == NULL && cur->right == NULL) return depth;
			}
		}
		return depth;
	}
};

11. 完全二叉树的节点个数

leetcode链接

方法一: 普通二叉树的做法,选定先/后/ 层序遍历之一,传入一个遍历,每轮遍历时加1,最后返回加和即可。

class Solution {
public:
	void preorder(TreeNode* root, int &count) {
		if (root == NULL) return;
		count++;
		preorder(root->left,count);
		preorder(root->right, count);
	}

	int countNodes(TreeNode* root) {
		if (root == NULL) return 0;
		int res = 0;
		preorder(root, res);
		return res;
	}
};

时间复杂度: O(n)
空间复杂度: O(logn)

方法二: 针对完全二叉树的方法,对于根节点,判断是否为满二叉树。若为满二叉树,直接返回2^h -1 (h为二叉树的高度);反之,则按照正常的二叉树递归返回结果。递归时,判断孩子结点时,也可判断是否为完全二叉树。

判断是否为满二叉树: 分别一直遍历最左孩子和最右孩子,并记录深度。当左右深度相等时,则为满二叉树;反之,则不是满二叉树。

class Solution {
public:
	int countNodes(TreeNode* root) {
		if (root == NULL) return 0;
		int leftheight = 0, rightheight = 0;
		TreeNode* l = root->left;
		TreeNode* r = root->right;
		while (l) {  // 求左边的深度
			leftheight++;
			l = l->left;
		}

		while (r) {
			rightheight++;
			r = r->right;
		}
		if (leftheight == rightheight)// 当左右深度相等时,为满二叉树,返回2^h-1
			return (2 << leftheight) - 1;  // 左移运算符 == 2 * 2^leftheight == 2^ h
		// 若为非满二叉树,则用普通的二叉树递归计算
		return countNodes(root->left) + countNodes(root->right) + 1;
	}
};

时间复杂度: O(logn * logn)

12. 平衡二叉树

leetcode链接

思路: 求深度可以从上到下去查 所以需要前序遍历(中左右),而高度只能从下到上去查,所以只能后序遍历(左右中),接收左右子树的高度,判断当前子树是否为平衡二叉树。

递归法(传入一个bool类型,判断当前子树是否为平衡二叉树):

class Solution {
public:
	int postorder(TreeNode* root, bool &isbalance) {
		if (root == NULL) return 0;
		int leftheight = postorder(root->left,isbalance);
		int rightheight = postorder(root->right,isbalance);
		if (leftheight - rightheight > 1 || rightheight - leftheight > 1)
			isbalance = false;
		return max(leftheight, rightheight) + 1;
	}

	bool isBalanced(TreeNode* root) {
		if (root == NULL) return true;
		bool isbalance = true;
		postorder(root, isbalance);
		return isbalance;
	}
};

递归法(不传入bool变量作为参数来传递,直接使用返回值是否为-1进行判断)

class Solution {
public:
	int postorder(TreeNode* root) {
		if (root == NULL) return 0;
		// 若当前子树的深度为-1,则该子树为非平衡二叉树
		int leftheight = postorder(root->left);
		if (leftheight == -1) return -1;
		int rightheight = postorder(root->right);
		if (rightheight == -1) return -1;
		if (leftheight - rightheight > 1 || rightheight - leftheight > 1)
			return -1;
		return max(leftheight, rightheight) + 1;
	}

	bool isBalanced(TreeNode* root) {
		if (root == NULL) return true;
		return postorder(root) == -1 ? false : true;
	}
};

13. 二叉树的所有路径

leetcode链接

思路: 本题需要使用递归加回溯,使用一个数组保存根到当前结点的路径,若当前节点为叶结点,则将路径转换为字符串添加进结果数组中;若当前结点为非叶结点,则判断其左孩子和右孩子是否为叶节点,且当当层递归完成,删除路径的末尾元素,进行回溯。回溯和递归是一一对应的,有一个递归,就要有一个回溯

class Solution {
public:
	void traversal(TreeNode* cur,vector<int>& path,vector<string> &res) {
		path.push_back(cur->val);  // 将当前结点的值加入路径中,叶节点的值也需加入
		if (cur->left == NULL && cur->right == NULL) {  // 左右孩子均为空,则找到叶节点
			string curPath = "";
			for (int i = 0; i < path.size() - 1; i++) { // 只添加n-1个,因为要单独加n-1个=》
				curPath += to_string(path[i]); // 将int转换为字符串加入结果
				curPath += "->";
			}
			curPath += to_string(path[path.size() - 1]); // 添加叶节点的值
			res.push_back(curPath);  // 添加结果
		}

		// 当不为叶节点时,保证下一层循环的 cur!= null
		if (cur->left) {
			traversal(cur->left, path, res);
			path.pop_back(); // 回溯,路径path去掉cur->left->val
		}
		if (cur->right) {
			traversal(cur->right, path, res);
			path.pop_back(); // 回溯,同理
		}
	}

	vector<string> binaryTreePaths(TreeNode* root) {
		vector<string> res;
		vector<int> path;// 使用int记录路径元素,当添加结果时,再进行转换
		if (root == NULL) return res;
		traversal(root, path, res);
		return res;
	}
};

14.二叉树周末总结

代码随想录:二叉树周末总结Ⅱ

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值