leetcode算法刷题的第十八天
1.leetcode 669.修剪二叉搜索树
题目链接
/*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode() : val(0), left(nullptr), right(nullptr) {}* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}* };*/
class Solution {
public:TreeNode* trimBST(TreeNode* root, int low, int high) {if(root==nullptr) return nullptr;if(root->val<low){TreeNode* right=trimBST(root->right,low,high);// 寻找符合区间[low, high]的节点return right;}if(root->val>high){TreeNode* left=trimBST(root->left,low,high);// 寻找符合区间[low, high]的节点return left;}root->left=trimBST(root->left,low,high);// root->left接入符合条件的左孩子root->right=trimBST(root->right,low,high);// root->right接入符合条件的右孩子return root;}
};
思路总结:如果不对递归有深刻的理解,这道题目还是有点难度的。因为二叉搜索树的特殊性,导致可能根节点的左孩子不符合条件,但是它的左孩子的右孩子可能符合条件,那如果一下子就把左孩子删除了,这样就会把左孩子的右孩子一起删除了,所以导致误删,所以我们还要再对左孩子的右孩子进行判断,那么右孩子的左孩子也是如此。
2.leetcode 108.将有序数组转换为二叉搜索树
题目链接
/*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode() : val(0), left(nullptr), right(nullptr) {}* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}* };*/
class Solution {
public://这里定义的区间就是左闭右闭,left和right都是数组的下标TreeNode* traversal(vector<int>& nums,int left,int right){if(left>right) return nullptr;//不合法区间int mid=left+((right-left)/2);TreeNode* root=new TreeNode(nums[mid]);//创建一个根节点root->left=traversal(nums,left,mid-1);//构造左子树root->right=traversal(nums,mid+1,right);//构造右子树return root;}TreeNode* sortedArrayToBST(vector<int>& nums) {TreeNode* node=traversal(nums,0,nums.size()-1);return node;}
};
思路总结:因为我们这里规定的区间是左闭右闭,所以求mid的时候不能直接(left+right)/2,这样会导致下面的递归函数出错,最好的办法是left+((right-left)/2),这样就可以完美解决这个问题。这道题的解法有点像二分查找,先把有序数组分成左右两边,然后再进行操作,这样就可以构造二叉搜索树,但是也要知道二叉搜索树的特点,才知道为什么要用这个方法。
3.leetcode 538.把二叉搜索树转换为累加树
题目链接
第一种解法:递归法
/*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode() : val(0), left(nullptr), right(nullptr) {}* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}* };*/
class Solution {
public:int pre=0;//记录前一个节点的数值void traversal(TreeNode* current){//右中左遍历if(current==nullptr) return;traversal(current->right);//右current->val+=pre;//中pre=current->val;traversal(current->left);//左}TreeNode* convertBST(TreeNode* root) {pre=0;traversal(root);return root;}
};
第二种解法:迭代法
/*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode() : val(0), left(nullptr), right(nullptr) {}* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}* };*/
class Solution {
public:int pre=0;//记录前一个节点的数值void traversal(TreeNode* root){stack<TreeNode*> st;//右中左 遍历顺序TreeNode* current=root;while(current!=NULL||!st.empty()){if(current!=NULL){st.push(current);current=current->right;//右}else{current=st.top();//中st.pop();current->val+=pre;pre=current->val;current=current->left;//左}}}TreeNode* convertBST(TreeNode* root) {pre=0;traversal(root);return root;}
};
思路总结:这道题的关键就是要清楚遍历顺序是什么,当然是右中左,这两种方法其实也不是很难,甚至可以看做是中序遍历的模板题,尤其是迭代法,就是中序遍历的模板,而这道题的遍历顺序可以看做反中序遍历,中序遍历是左中右,所以这道题还是比较简单的。
4.二叉树总结
(1)理论基础
二叉树的种类,存储方式,遍历方式,定义方式。这些在我第一篇二叉树的博客里面有具体的介绍。
(2)二叉树的遍历方式
深度优先遍历(前中后序遍历)、广度优先遍历(层序遍历,要用队列来模拟)。
(3) 求二叉树的属性
(4)二叉树的修改与构造
(5)求二叉搜索树的属性
(6)二叉树的公共祖先问题
(7)二叉搜索树的修改与构造
(8)最后总结
在二叉树题目选择什么遍历顺序是不少同学头疼的事情
涉及到二叉树的构造,无论普通二叉树还是二叉搜索树一定前序,都是先构造中节点。
求普通二叉树的属性,一般是后序,一般要通过递归函数的返回值做计算。
求二叉搜索树的属性,一定是中序了,要不白瞎了有序性了。
注意在普通二叉树的属性中,我用的是一般为后序,例如单纯求深度就用前序。