题目链接
代码随想录文章讲解链接
/*
// Definition for a Node.
class Node {
public:
int val;
Node* left;
Node* right;
Node* next;
Node() : val(0), left(NULL), right(NULL), next(NULL) {}
Node(int _val) : val(_val), left(NULL), right(NULL), next(NULL) {}
Node(int _val, Node* _left, Node* _right, Node* _next)
: val(_val), left(_left), right(_right), next(_next) {}
};
*/
class Solution {
public:
Node* connect(Node* root) {
queue<Node*> que;
if (root == NULL) return root;
que.push(root);
while (!que.empty()) {
int size = que.size();
for (int i = 0; i < size; ++i) {
Node* node = que.front();
que.pop();
if (i < size - 1) node->next = que.front();
if (node->left) que.push(node->left);
if (node->right) que.push(node->right);
}
}
return root;
}
};
用时:29m27s
利用当前层已经通过next指针相连的性质,将下一层的节点连起来。
设置一个虚拟头结点dummy,用于指向下一层最左端的节点,初始化时让其指向NULL。
在当前层中,从左往右寻找下一层的子节点,将其逐个相连。
下一层的节点相连完成后,下一层的节点变为当前层节点,然后继续往下处理。
class Solution {
public:
Node* connect(Node* root) {
Node* cur = root;
Node* dummy = new Node();
while (cur != NULL) {
dummy->next = NULL; // 用于指向下一层最左边的节点
Node* pre = dummy;
while (cur != NULL) {
if (cur->left) {
pre->next = cur->left;
pre = pre->next;
}
if (cur->right) {
pre->next = cur->right;
pre = pre->next;
}
cur = cur->next;
}
cur = dummy->next; // 进入下一层,cur更新为下一层最左边的节点
}
return root;
}
};
无。
无。
题目链接
代码随想录文章讲解链接
在递归的同时维护一个字符串str
。
递归的逻辑:
str
中添加当前节点的数值。str
添加到答案数组res
中。str
中删除,因为回到上一层递归后,此时的路径已经不包括当前的节点了。class Solution {
public:
vector<string> binaryTreePaths(TreeNode* root) {
vector<string> res;
string str;
traversal(root, res, str);
return res;
}
void traversal(TreeNode* node, vector<string>& res, string& str) {
// 路径添加当前节点
if (!str.empty()) str += "->";
str += to_string(node->val);
// 若是叶子节点则记录路径,否则左右子节点递归
if (node->left == nullptr && node->right == nullptr) res.push_back(str);
else {
if (node->left) traversal(node->left, res, str);
if (node->right) traversal(node->right, res, str);
}
// 回溯
int pos = str.rfind("->");
if (pos >= 0) str.erase(pos, str.size() - pos);
}
};
用时:6m36s
在二叉树BFS的基础上,额外创建一个队列用于存放路径。
nodeQue
用于存放节点,pathQue
用于存放路径,且对于两个队列中同一位置的元素n_i
和p_i
,p_i
表示从根节点到节点n_i
的路径。
循环内部:
若nodeQue队头的节点是叶子节点,则pathQue队头的路径就是根节点到该叶子节点的路径,将该路径保存至结果数组res中。
若nodeQue队头的节点不是叶子节点,则将其左右节点入队nodeQue,并且pathQue也入队相应的路径,即为(当前路径)->(子节点数值)。
class Solution {
public:
vector<string> binaryTreePaths(TreeNode* root) {
vector<string> res;
queue<TreeNode*> nodeQue; // 存放节点的队列
queue<string> pathQue; // 存放字符串的队列
// BFS
nodeQue.push(root);
pathQue.push(to_string(root->val));
while (!nodeQue.empty()) {
TreeNode* node = nodeQue.front();
string path = pathQue.front();
nodeQue.pop();
pathQue.pop();
if (node->left == nullptr && node->right == nullptr) res.push_back(path); // 当前节点为叶子节点,将路径添加到答案数组中
else {
if (node->left) {
nodeQue.push(node->left);
pathQue.push(path + "->" + to_string(node->left->val)); // 在当前路径的基础上,增加左子节点
}
if (node->right) {
nodeQue.push(node->right);
pathQue.push(path + "->" + to_string(node->right->val)); // 在当前路径的基础上,增加右子节点
}
}
}
return res;
}
};
回溯都来了,这是简单题?
无。
题目链接
代码随想录文章讲解链接
用curSum记录当前左叶子节点之和。
对于当前节点,若左节点存在,且左节点是叶子节点,则将curSum加上左节点的数值;否则左节点继续递归。然后再对右节点递归。
class Solution {
public:
int sumOfLeftLeaves(TreeNode* root) {
int res = 0;
_sumOfLeftLeaves(root, res);
return res;
}
void _sumOfLeftLeaves(TreeNode* node, int& curSum) {
if (node->left) {
if (node->left->left == nullptr && node->left->right == nullptr) curSum += node->left->val;
else _sumOfLeftLeaves(node->left, curSum);
}
if (node->right) _sumOfLeftLeaves(node->right, curSum);
}
};
用时:5m3s
class Solution {
public:
int sumOfLeftLeaves(TreeNode* root) {
queue<TreeNode*> que;
int res = 0;
que.push(root);
while (!que.empty()) {
TreeNode* node = que.front();
que.pop();
if (node->left) {
if (node->left->left == nullptr && node->left->right == nullptr) res += node->left->val;
else que.push(node->left);
}
if (node->right) que.push(node->right);
}
return res;
}
};
无。
无。
题目链接
代码随想录文章讲解链接
用时:5m10s
class Solution {
public:
int findBottomLeftValue(TreeNode* root) {
queue<TreeNode*> que;
int res;
que.push(root);
while (!que.empty()) {
res = que.front()->val;
int size = que.size();
for (int i = 0; i < size; ++i) {
TreeNode* node = que.front();
que.pop();
if (node->left) que.push(node->left);
if (node->right) que.push(node->right);
}
}
return res;
}
};
使用curHeight
来记录最高的节点的高度,使用curVal
来记录最高高度时最左边节点的值。用height
来记录当前节点的高度,每一层递归都加一。
如果当前节点的高度大于最大高度,则更新curHeight
和curVal
。
class Solution {
public:
void dfs(TreeNode *root, int height, int &curVal, int &curHeight) {
if (root == nullptr) {
return;
}
height++;
dfs(root->left, height, curVal, curHeight);
dfs(root->right, height, curVal, curHeight);
// 如果当前节点的高度大于最大高度,则更新curHeight和curVal
// 值的比较用“大于”,这样只有第一达到最大高度时才会被记录,而我们事先遍历左节点,所以记录的一定是最大高度最左边的节点的值
if (height > curHeight) {
curHeight = height;
curVal = root->val;
}
}
int findBottomLeftValue(TreeNode* root) {
int curVal, curHeight = 0;
dfs(root, 0, curVal, curHeight);
return curVal;
}
};
题目链接
代码随想录文章讲解链接
用时:18m38s
用curSum来记录根节点到当前节点的路径和。
class Solution {
public:
bool hasPathSum(TreeNode* root, int targetSum) {
return root == nullptr ? false : dfs(root, 0, targetSum);
}
bool dfs(TreeNode* node, int curSum, int targetSum) {
// 更新根节点到当前节点的路径和
curSum += node->val;
// 如果当前节点是叶子节点,则返回路径和是否等于目标值
if (node->left == nullptr && node->right == nullptr) return curSum == targetSum;
// 如果左或右节点存在,并且存在路径和等于目标值,则返回true,否则返回false
if (node->left && dfs(node->left, curSum, targetSum)) return true;
if (node->right && dfs(node->right, curSum, targetSum)) return true;
return false;
}
};
方法一是在DFS中,不断更新当前的路径和,当到达叶子节点后判断当前和是否等于目标值。
可以换一个角度来使用DFS解本题,每次递归更新目标值,每向下递归一个节点,则目标值减去当前结点的值,到达叶子节点时,若叶子结点的值与剩余的目标值相同,则说明根节点到当前的叶子结点的路径和与初始目标值相等。
递归逻辑:
class Solution {
public:
bool hasPathSum(TreeNode* root, int targetSum) {
if (root == nullptr) return false;
if (root->left == nullptr && root->right == nullptr) return root->val == targetSum;
return hasPathSum(root->left, targetSum - root->val) || hasPathSum(root->right, targetSum - root->val);
}
};
用栈实现DFS,栈存储的元素是pair,pair记录着当前节点以及根节点到当前节点的路径和。
class Solution {
public:
bool hasPathSum(TreeNode* root, int targetSum) {
if (root == nullptr) return false;
stack<pair<TreeNode*, int>> st;
st.push(pair<TreeNode*, int>(root, root->val));
while (!st.empty()) {
TreeNode* node = st.top().first;
int curSum = st.top().second;
st.pop();
if (node->left == nullptr && node->right == nullptr && curSum == targetSum) return true;
if (node->left) st.push(pair<TreeNode*, int>(node->left, curSum + node->left->val));
if (node->right) st.push(pair<TreeNode*, int>(node->right, curSum + node->right->val));
}
return false;
}
};
时间:12m51s
在BFS的基础上,加多一个队列用于记录路径和。
class Solution {
public:
bool hasPathSum(TreeNode* root, int targetSum) {
if (root == nullptr) return false;
queue<TreeNode*> nodeQue;
queue<int> sumQue;
nodeQue.push(root);
sumQue.push(root->val);
while (!nodeQue.empty()) {
TreeNode* node = nodeQue.front();
int curSum = sumQue.front();
nodeQue.pop();
sumQue.pop();
if (node->left == nullptr && node->right == nullptr && curSum == targetSum) return true;
if (node->left) {
nodeQue.push(node->left);
sumQue.push(curSum + node->left->val);
}
if (node->right) {
nodeQue.push(node->right);
sumQue.push(curSum + node->right->val);
}
}
return false;
}
};
无。
无。
感觉二叉树的题目搞来搞去基本都是在DFS和BFS的基础上变动。