代码随想录算法训练营第20天 | 654.最大二叉树 617.合并二叉树 700.二叉搜索树中的搜索 98.验证二叉搜索树

最大二叉树

Alt
Alt
Alt
思路上这道题与昨天的从遍历数组构造二叉树那道题是一致的,也是进行一层一层的递归。有几点需要注意:这种题最好不要在递归函数中进行数组的切分,而是尽量用下标作为递归参数,可以减小时间和空间。另外,递归终止条件是叶子节点还是空指针,与递归时是否需要验证数组长度为0是相互对应的

class Solution{
public:
	TreeNode* traversal(vector<int>& nums, int left, int right){
		if(left == right)  return NULL;
		int maxIndex = left;
		for(int i = left + 1; i < right; i++){
			if(nums[i] > nums[maxIndex]){
				maxIndex = i;
			}
		}
		TreeNode* root = new TreeNode(nums[maxIndex]);
		root->left = traversal(nums, left, maxIndex);
		root->right = traversal(nums, maxIndex + 1, right);
		return root;
	}
	TreeNode* constructMaximumBinaryTree(vector<int>& nums){
		return traversal(nums, 0, nums.size());
	}
};

合并二叉树

Alt
与对称二叉树那道题比较相似,这道题也是处理两个二叉树,我们仍然是先实现递归法。

class Solution{
public:
	TreeNode* mergeTrees(TreeNode* root1, TreeNode* root2){
		if(!root2)  return root1;  // 如果root2为空,那么返回root1作为节点,这样就不需要继续处理root1的子树了
		if(!root1)  return root2;
		// 两个树的当前节点都不为空
		TreeNode* root = new TreeNode(0);
		root->val = root1->val + root2->val;
		root->left = mergeTrees(root1->left, root2->left);
		root->right = mergeTrees(root1->right, root2->right);
		return root;
	}
};

对于中间节点的加和处理,前中后序都是可以的。
迭代法中,一般一起操作两个树都是使用队列模拟层序遍历,同时处理两个树的节点

class Solution{
public:
	TreeNode* mergeTrees(TreeNode* root1, TreeNode* root2){
		if(!root2)  return root1;
		if(!root1)  return root2;
		// 两个树都不空
		queue<TreeNode*> que;
		que.push(root1);
		que.push(root2);
		while(!que.empty()){
			TreeNode* node1 = que.front();
			que.pop();
			TreeNode* node2 = que.front();
			que.pop();
			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);
			}
			// 如果第一棵树的子节点为空,就把第二棵树的节点接上来
			if(node1->left == NULL && node2->left != NULL){
				node1->left = node2->left;
			}
			if(node1->right == NULL && node2->right != NULL){
				node1->right = node2->right;
			}
			// 如果第二棵树的子节点是空的,则不需要进一步处理第一棵树子节点了,不用入队列
		}
		return root1;
	}
};

二叉搜索树中的搜索

由于二叉搜索树的性质,我们可以使用一些更简单的方法遍历节点。

class Solution{
public:
	TreeNode* searchBST(TreeNode* root, int val){
		// 返回条件,如果遇到了空节点或者找到了相等值,将节点返回
		if(root == NULL || root->val == val)  return root;
		TreeNode* result;  // 按值来判断向左还是向右遍历
		if(val > root->val)  result = searchBST(root->right, val);
		if(val < root->val)  result = searchBST(root->left, val);
		return result;
	}
};

迭代法也比之前的栈模拟或队列模拟更简单。由于二叉搜索树的有序性,遍历是不需要回溯的,方向是确定的。

class Solution{
public:
	TreeNode* searchBST(TreeNode* root, int val){
		while(root != NULL){
			if(val < root->val)  root = root->left;
			else if(val > root->val)  root = root->right;
			else  return root;
		}
		return root;
	}
};

验证二叉搜索树

二叉搜索树的中序遍历序列是一个单调递增序列

class Solution{
public:
	void traversal(TreeNode* node, vector<int>& vec){
		if(node == NULL)  return;
		traversal(node->left, vec);
		vec.push_back(node->val);
		traversal(node->right, vec);
	}
	bool isValidBST(TreeNode* root){
		if(!root)  return true;
		vector<int> vec;
		traversal(root, vec);
		for(int i = 1; i < vec.size(); i++){
			if(vec[i] <= vec[i - 1])  return false;
		}
		return true;
	}
};

我们也可以在中序遍历过程同时进行比较递归的方法。必须注意两点:

  1. 不能单单判断左右子节点和父节点之间的关系。而是判断左右子树与父节点之间的关系。
  2. 注意给出的测试示例,存在元素值比INT_MIN要小的情况,所以需要定义最小值为long long maxVal = LONG_MIN

这道题也是不需要遍历整个树,遇到不满足的情况及时返回就行,所以递归函数需要返回值来判断。

class Solution{
public:
	long long maxVal = LONG_MIN;
	bool isValidBST(TreeNode* root){
		if(root == NULL)  return true;  // 二叉搜索树可以为空
		// 中序遍历
		if(!isValidBST(root->left))  return false;
		if(maxVal < root->val)  maxVal = root->val;  // 处理中间节点,与中序上一个节点的值比较,确保单调递增
		else  return false;
		if(!isValidBST(root->right))  return false;
		return true;
	}
};

也可以迭代法来实现中序遍历。这里注意变量的定义域,不要在循环内部新建同名节点,循环时判断时不会更新的

class Solution{
public:
	bool isValidBST(TreeNode* root){
		if(root == NULL)  return true;
		stack<TreeNode*> st;
		TreeNode* cur = root;
		TreeNode* pre = NULL;
		while(cur != NULL || !st.empty()){
			if(cur != NULL){
				cur = cur->left;
				st.push(cur);
			}
			else{
				cur = st.top();
				st.pop();
				if(pre != NULL && pre->val >= cur->val)  return false;
				pre = cur;
				cur = cur->right;
			}
		}
		return true;
	}
};
  • 9
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值