144.二分木のプレオーダートラバーサル
トピック:
二分木が与えられた場合、そのプレオーダー トラバーサルを返し ます。
例:
输入: [1,null,2,3] 1 \ 2 / 3 输出: [1,2,3]
解決策1:再帰
class Solution {
private:
void takeVal(TreeNode *root, vector<int>& res) {
if (NULL == root)
return;
res.push_back(root->val);
takeVal(root->left, res);
takeVal(root->right, res);
}
public:
vector<int> preorderTraversal(TreeNode* root) {
vector<int> res;
if (NULL == root)
return res;
takeVal(root, res);
return res;
}
};
解決策2:スタックを使用し、最初に右側のサブツリーを入力してから、左側のサブツリーを入力します
class Solution {
public:
vector<int> preorderTraversal(TreeNode* root) {
vector<int> res;
if (NULL == root)
return res;
stack<TreeNode*> sta;
TreeNode* node;
sta.push(root);
while (!sta.empty()) {
node = sta.top();
sta.pop();
res.push_back(node->val);
if (node->right)
sta.push(node->right);
if (node->left)
sta.push(node->left);
}
return res;
}
};
解決策3:スタックを使用し、右側のサブツリーのみを押す
class Solution {
public:
vector<int> preorderTraversal(TreeNode* root) {
vector<int> res;
if (NULL == root)
return res;
stack<TreeNode*> sta;
TreeNode* node = root;
while (true) {
if (node) {
res.push_back(node->val);
if (node->right)
sta.push(node->right);
node = node->left;
} else {
if (sta.empty())
break;
node = sta.top();
sta.pop();
}
}
return res;
}
};
145.二分木のポストオーダートラバーサル
トピック:
二分木が与えられた場合、そのポストオーダー トラバーサルを返し ます。
例:
输入: [1,null,2,3] 1 \ 2 / 3 输出: [3,2,1]
解決策1:再帰
class Solution {
private:
void takeVal(TreeNode *root, vector<int>& res) {
if (NULL == root)
return;
takeVal(root->left, res);
takeVal(root->right, res);
res.push_back(root->val);
}
public:
vector<int> postorderTraversal(TreeNode* root) {
vector<int> res;
if (NULL == root)
return res;
takeVal(root, res);
return res;
}
};
解決策2:スタックを使用して左右の子ノードをプッシュします
class Solution {
public:
vector<int> postorderTraversal(TreeNode* root) {
vector<int> res;
if (NULL == root)
return res;
stack<TreeNode*> sta;
TreeNode* node;
sta.push(root);
while (!sta.empty()) {
node = sta.top();
root = node; //在处理其子节点前,记住这个节点
while (node->left) { //处理左子树
node = node->left;
root->left = NULL; //节点左指针剪枝,避免无限重复访问
sta.push(node);
root =node;
}
if (root->right) { //转向右子树,重复处理其左子树
node = root->right;
root->right = NULL; //节点右指针剪枝
sta.push(node);
root = node;
} else { //没有左子树,没有右子树,即压入节点
res.push_back(root->val);
sta.pop();
}
}
return res;
}
};
このソリューションが呼び出された後、ツリー構造が変更されます。つまり、ツリーはノードに分割されます。
解決策3:スタックを使用して左右の子ノードをプッシュし、補助マーカーノードを使用して親ノードと子ノードを分離し、元のツリーを変更しないでください
class Solution {
public:
vector<int> postorderTraversal(TreeNode* root) {
vector<int> res;
if (NULL == root)
return res;
stack<TreeNode*> sta;
TreeNode* node;
sta.push(root);
while (!sta.empty()) {
node = sta.top();
if (node) { //父节点是栈的top()
sta.push(NULL); //在父节点和其孩子节点之间加一个标记
if (node->right)
sta.push(node->right);
if (node->left)
sta.push(node->left);
} else {
sta.pop(); //弹出标记的空节点
node = sta.top();
sta.pop();
res.push_back(node->val);
}
}
return res;
}
};
解決策4:解決策3に基づいて、前、中、後の順序でトラバースできるテンプレートを作成します
class Solution {
public:
vector<int> postorderTraversal(TreeNode* root) {
vector<int> res;
if (NULL == root)
return res;
stack<TreeNode*> sta;
TreeNode* node;
sta.push(root);
while (!sta.empty()) {
node = sta.top();
sta.pop(); //弹出该节点
if (node) {
sta.push(node); //先压入该父节点
sta.push(NULL);
if (node->right)
sta.push(node->right);
if (node->left)
sta.push(node->left);
} else { //标记节点已弹出
node = sta.top();
sta.pop();
res.push_back(node->val);
}
}
return res;
}
};
現在の親ノードにポップインすることにより、親ノードとその子ノードの相対位置が変更されます。このソリューションは、if(ノード)のステートメントの相互順序をわずかに変更して、プレオーダー、ミドルオーダー、およびポストオーダーのトラバーサルを実現します。
if(node)を変更し、最後に親ノードを押して、テンプレートの下でプレオーダートラバーサルを取得します。具体的な手順は次のとおりです。
class Solution {
public:
vector<int> preorderTraversal(TreeNode* root) {
vector<int> res;
if (NULL == root)
return res;
stack<TreeNode*> sta;
TreeNode* node;
sta.push(root);
while (!sta.empty()) {
node = sta.top();
sta.pop();
if (node) {
if (node->right)
sta.push(node->right);
if (node->left)
sta.push(node->left);
sta.push(node); //最后压入父节点
sta.push(NULL);
} else {
node = sta.top();
sta.pop();
res.push_back(node->val);
}
}
return res;
}
};
if(node)を変更し、中央の親ノードを押して、テンプレートの下で中間次の走査を取得します。具体的な手順は次のとおりです。
class Solution {
public:
vector<int> preorderTraversal(TreeNode* root) {
vector<int> res;
if (NULL == root)
return res;
stack<TreeNode*> sta;
TreeNode* node;
sta.push(root);
while (!sta.empty()) {
node = sta.top();
sta.pop();
if (node) {
if (node->right)
sta.push(node->right);
sta.push(node); //中间压入父节点
sta.push(NULL);
if (node->left)
sta.push(node->left);
} else {
node = sta.top();
sta.pop();
res.push_back(node->val);
}
}
return res;
}
};
94.二分木の順序通りの走査
トピック:
二分木が与えられた場合、その中次 走査を返します。
解決策1:再帰
class Solution {
private:
void inorderRes(TreeNode *root, vector<int> &res) {
if (NULL == root)
return;
if (root->left)
inorderRes(root->left, res);
res.push_back(root->val);
if (root->right)
inorderRes(root->right, res);
}
public:
vector<int> inorderTraversal(TreeNode* root) {
vector<int> res;
if (NULL == root)
return res;
inorderRes(root, res);
return res;
}
};
解決策2:nullポインターを使用して親ノードをマークします
class Solution {
public:
vector<int> inorderTraversal(TreeNode* root) {
vector<int> res;
if (NULL == root)
return res;
stack<TreeNode*> sta;
sta.push(root);
TreeNode *node;
while (!sta.empty()) {
node = sta.top();
sta.pop();
if (node) {
if (node->right)
sta.push(node->right);
sta.push(node);
sta.push(NULL);
if (node->left)
sta.push(node->left);
} else {
node = sta.top();
sta.pop();
res.push_back(node->val);
}
}
return res;
}
};
解決策3:スタックを使用して、ルートから常に右側のサブツリーをプッシュし、出力を中間の順序でトラバースします
class Solution {
public:
vector<int> inorderTraversal(TreeNode* root) {
vector<int> res;
if (NULL == root)
return res;
stack<TreeNode*> sta;
TreeNode *node = root;
while (node || !sta.empty()) {
while (node) {
sta.push(node);
node = node->left;
}
node = sta.top();
sta.pop();
res.push_back(node->val);
node = node->right;
}
return res;
}
};