我们在做关于树的问题时常常用到递归,关于递归,我觉得最核心的一点就是递归的单层逻辑的目的,即递归的代码从本质来说要完成什么。并且在构建单层逻辑和使用的时候记住这个目的。
知道了单层逻辑,则返回值,参数,截止条件这些也就不难写了。
例如下面这题:
这一题很明显可以用递归,那么递归的单层逻辑是什么呢,就是使当前递归到的结点成为一个合格的结点。
在使用的时候要记住这个目的。在构建的时候要细化这个目的。
构建与使用又是一体的。目的是合格的结点,什么叫合格呢?即当前节点的值满足要求,并且其左右结点(子树)的值也满足要求,那么构建的时候就先检查值是否正确,若不正确,则从相应子树中找一个结点作为正确的结点,这个时候就可直接使用该函数了。若值正确,则要构建合格的左右结点。代码如下:
/**
* 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) return nullptr;
if (root->val > high) {
TreeNode *left = trimBST(root->left, low, high);
return left;
}
if (root->val < low) {
TreeNode *right = trimBST(root->right, low, high);
return right;
}
root->left = trimBST(root->left, low, high);
root->right = trimBST(root->right, low, high);
return root;
}
};
为什么在检查了值之后得到一个节点left或者right可以直接返回而不用检查左右子节点,因为单层逻辑是获得合格的节点,所以使用了该函数后得到的已经是个合格的结点,可以直接返回了。
所以树的递归的核心是利用单层逻辑进行构建和使用。