二叉树的所有路径
因为需要遍历整棵二叉树,获取所有的节点,并且回溯的过程不需要处理信息。故采用没有返回值的回溯算法。回溯与递归差不多。但它主要的区别是它在遍历的过程中,有着保存元素的动作,并且伴随着函数帧的调用,有着对元素push/pop的动作。 这主要有两种形式,一种是在函数调用时构造临时值(值传递),无需有显示的pop操作;另一种是引用传递或者采用全局变量保存中间值,这样在每个函数返回的时候都需要有显示的pop操作。本题便是采用构造临时变量进行值传递的做法。
* 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:
vector<string> result;
void backtrack(TreeNode* root, string path) {
//遇到空节点则返回
if(root == nullptr) return;
//遇到叶子节点则添加末尾,并添加到结果中
if(root->left == nullptr && root->right == nullptr) {
path += to_string(root->val);
result.push_back(path);
}
//值传递+临时构造参数,相当于回溯,故没有显示的pop操作
backtrack(root->left, path + to_string(root->val) + "->");
backtrack(root->right, path + to_string(root->val) + "->");
}
vector<string> binaryTreePaths(TreeNode* root) {
backtrack(root, "");
return result;
}
};
二叉树的路径总和Ⅰ
第一种做法较为简略,但需要遍历整个二叉树。
/**
* 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:
bool hasPathSum(TreeNode* root, int targetSum) {
/*遇到为空的非叶子节点返回false*/
if(root == nullptr) return false;
/*叶子节点,且值为0返回true*/
if(!root->left && !root->right) {
return !(targetSum - root->val);
}
return hasPathSum(root->left, targetSum - root->val) ||
hasPathSum(root->right, targetSum - root->val);
}
};
或者采用以下做法,带有返回值的递归,可以避免递归所有子树。
* 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:
bool search(TreeNode* root, int targetSum) {
if(!root->left && !root->right) {
return !(targetSum - root->val);
}
if(root->left) {
if(search(root->left, targetSum - root->val)) return true;
}
if(root->right) {
if(search(root->right, targetSum - root->val)) return true;
}
return false;
}
bool hasPathSum(TreeNode* root, int targetSum) {
if(root == nullptr) return false;
return search(root, targetSum);
}
};
二叉树的路径总和Ⅱ
本题要求找到所有符合要求的路径。采用vector保存路径,只能采用引用或者全局变量的做法。在递归调用子函数返回后,必须对元素进行弹出。这里还有一个细节,就是调用函数前要不要对子节点进行判断非空。如果不判断的话,形式如下:
if(root == nullptr) return;
if(!root->left && !root->right && targetSum - root->val == 0) {
result.push_back(path);
}
backtrack(root->left);
path.pop_back();
backtrack(root->right);
path.pop_back();
若调用前不判断非空,则函数的第一句必须判断节点是否为空,若为空则返回。但在采用全局变量或者采用引用,有着显式的push/pop操作的递归时,必须在调用前判断是否非空。否则会因为遇到空节点返回,没有push元素,返回后缺多弹出了一个元素,引发错误。
* 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:
vector<vector<int>> result;
vector<int> path;
void backtrack(TreeNode* root, int targetSum) {
/*将当前层的节点放入path中保存*/
path.push_back(root->val);
if(!root->left && !root->right) {
if(targetSum - root->val == 0) {
result.push_back(path);
}
return;
}
/*对于采用非值传递保存中间结果的回溯题,必须先判非空再递归
因为若采用“先污染再治理”的办法,遇到空节点则返回
在空节点这层没有Push节点,返回的时候却错误地pop了节点*/
if(root->left) {
backtrack(root->left, targetSum - root->val);
path.pop_back();
}
if(root->right) {
backtrack(root->right, targetSum - root->val);
path.pop_back();
}
}
vector<vector<int>> pathSum(TreeNode* root, int targetSum) {
backtrack(root, targetSum);
return result;
}
};
二叉树的路径总和Ⅲ
思路与上一题类似,只不过需要有个嵌套调用。分别尝试以每个节点作为根节点寻找满足的路径。
* 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 cnt = 0;
/*采用值传递,无显示的push/pop操作,故递归的时候不需要判非空*/
void backtrack(TreeNode* root, long long targetSum) {
if(root == nullptr) return;
if(targetSum - root->val == 0) {
cnt++;
}
backtrack(root->left, targetSum - root->val);
backtrack(root->right, targetSum - root->val);
}
void traversal(TreeNode* root, int targetSum) {
if(root == nullptr) return;
backtrack(root, targetSum);
traversal(root->left, targetSum);
traversal(root->right, targetSum);
}
int pathSum(TreeNode* root, int targetSum) {
if(root == nullptr) return 0;
traversal(root, targetSum);
return cnt;
}
};
二叉树最大路径和
对于每个节点的贡献度,只需要计算当前root->val和子节点贡献度的较大值的和。而对于路径和而言,则情况特别多,通过在返回的时候和0比较取较大值,避免了各种情况的讨论。因为取0的时候相当于没有加上。
* 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 maxnum = INT32_MIN;
int maxgain(TreeNode* root) {
if(root == nullptr) return 0;
int leftGain = max(maxgain(root->left), 0);
int rightGain = max(maxgain(root->right), 0);
int num = root->val + leftGain + rightGain;
maxnum = max(maxnum, num);
return root->val + max(leftGain, rightGain);
}
int maxPathSum(TreeNode* root) {
if(root == nullptr) return 0;
maxgain(root);
return maxnum;
}
};
二叉树中的伪回文路径
在遍历的时候不保存路径节点序列,而是直接保存节点值得出现次数。就避免了超时。
* 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 count = 0;
unordered_map<int, int> map;
void backtrack(TreeNode* root) {
/*必须是叶子节点,而不是遇到空节点*/
map[root->val]++;
if(!root->left && !root->right) {
int cnt = 0;
for(auto ite : map) {
if(ite.second % 2 == 1) cnt++;
}
if(cnt <= 1) count++;
}
if(root->left) {
backtrack(root->left);
map[root->left->val]--;
}
if(root->right) {
backtrack(root->right);
map[root->right->val]--;
}
}
int pseudoPalindromicPaths (TreeNode* root) {
backtrack(root);
return count;
}
};