做了这个之后的感想,大概是两点,虽然说这两点都是常识吧:第一是在和树相关的题目上,递归不是万能的,像层次遍历levelOrder这种的还得用辅助队列迭代;第二是在递归的过程中可以用参数来保存状态。
树的最大深度这个问题,我看官方题解(包括算法书上)给出的是那种语义化的解法,也就是这种:
int maxDepth(TreeNode *root) { if (root == nullptr) { return 0; } int left_max = maxDepth(root->left); int right_max = maxDepth(root->right); return std::max(left_max, right_max) + 1; }这种解法的语义很好,但我感觉占的空间会比较大,因为每一步都需要保存一个返回值,所以我就用参数来传状态了:
int max = 0; void countDepth(TreeNode *root, int depth) { if (root == nullptr) { if (depth > max) { max = depth; } return; } ++depth; countDepth(root->left, depth); countDepth(root->right, depth); } int maxDepth(TreeNode *root) { countDepth(root, 0) return max; }至于层次遍历,一般来说层次遍历似乎是不得不用辅助队列进行迭代的。所以索性就用迭代做了:
vector<vector<int>> levelOrderBottom(TreeNode *root) { vector<vector<int>> result; if (root == nullptr) { return result; } result.push_back({root->val}); queue<TreeNode *> record; record.push(root); while (!record.empty()) { vector<int> vec; queue<TreeNode *> temp; while (!record.empty()) { root = record.front(); if (root->left) { vec.push_back(root->left->val); temp.push(root->left); } if (root->right) { vec.push_back(root->right->val); temp.push(root->right); } record.pop(); } if (vec.size()) { result.push_back(vec); } while (!temp.empty()) { record.push(temp.front()); temp.pop(); } } reverse(result.begin(), result.end()); return result; }可以感觉到这个代码是非常丑陋了。其实思路很简单,就是每一层提前处理下一层,把下一层的内容放进去。因为题目要求最后还得倒序,所以还多了一个翻转的过程;每一步还得用另一个辅助队列去存下一层的内容。
后来看到一个递归的解法,虽然说也是差不多的思路(并且也用了很多队列,笑),但是我觉得这个解法给我提了个醒,递归还可以这样用:
void levelOrderBottom(queue<TreeNode *> que, vector<vector<int>> &ans) { if (que.empty()) return; queue<TreeNode *> queNext; vector<int> vec; while (!que.empty()) { TreeNode *pNode = que.front(); que.pop(); vec.push_back(pNode->val); if (pNode->left != nullptr) queNext.push(pNode->left); if (pNode->right != nullptr) queNext.push(pNode->right); } levelOrderBottom(queNext, ans); // 我想说的是这一句 ans.push_back(vec); } vector<vector<int>> levelOrderBottom(TreeNode* root) { vector<vector<int>> ans; queue<TreeNode *> q; if (root != nullptr) q.push(root); levelOrderBottom(q, ans); return ans; }我现在觉得,中间件这个东西,是不是就是从递归中脱胎而出的。
另外吧,我感觉迭代相比起递归有一个特点,就是完全按照从前到后的顺序进行。这个倒不是指的下标啥的,因为可以倒序遍历,我指的是那种先到达最底层再逐层往上的能力。可能这就是子问题吧。
