题目地址:
https://leetcode.com/problems/construct-binary-tree-from-string/
给定一个长 n n n字符串 s s s,只含左括号、右括号、负号和 0 ∼ 9 0\sim 9 0∼9的数字。要求将其构造为一棵二叉树。构造规则是这样的,字符串要么是空串(则返回空树),要么以一个数开头(可正可负),后面接着两块括号,第一个括号内是左子树对应的字符串,第二个是右子树对应的字符串(当然也可能只有左子树没有右子树,此时只接一块括号)。返回树根。
法1:递归。设一个函数 f f f可以以当前走到的下标 u u u和 s s s作为参数,其能保证 s [ u ] s[u] s[u]要么是数字(也可能是 − - −),要么 u u u走到末尾;其功能是,构造以 s [ u ] s[u] s[u]数字的二叉树,并且将 u u u移到该二叉树的子串的后一个位置。那么 f ( 0 , s ) f(0,s) f(0,s)即为所求。考虑如何实现 f f f。如果 u u u已经指向末尾,则无法构造树,返回null;否则先截取出数字,并让 u u u越过该数字。现在 u u u如果没有指向 ( ( ((或者 u u u指向了末尾),就说明这个 s [ u ] s[u] s[u]的子树只有一个节点,此时 u u u是满足要求的,可以直接返回树根;如果 u u u指向了左括号,则递归求解左子树,如果接下来 u u u还是指向了左括号,说明右子树存在,递归求解右子树。最后返回树根。代码如下:
/**
* 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* str2tree(string s) {
int idx = 0;
return dfs(idx, s);
}
TreeNode* dfs(int& idx, string& s) {
if (idx == s.size()) return nullptr;
int sign = 1;
if (s[idx] == '-') sign = -1, idx++;
int i = idx;
while (idx < s.size() && isdigit(s[idx])) idx++;
auto root = new TreeNode(sign * stoi(s.substr(i, idx - i)));
if (idx < s.size() && s[idx] == '(') {
// 略过左括号,然后递归求解左子树,接着略过右括号
idx++;
root->left = dfs(idx, s);
idx++;
}
if (idx < s.size() && s[idx] == '(') {
// 与上同
idx++;
root->right = dfs(idx, s);
idx++;
}
return root;
}
};
时间复杂度 O ( n ) O(n) O(n),空间 O ( h ) O(h) O(h)。
法2:栈。遇到数字或负号,则先解析出数字,然后new出节点,如果栈空,则直接将节点入栈,否则看一下栈顶的左孩子是否空,如果空,则append到左边,否则append到右边,接着将new出的节点入栈;如果遇到右括号,则pop栈顶;遇到左括号直接忽略。代码如下:
class Solution {
public:
TreeNode* str2tree(string s) {
stack<TreeNode*> stk;
for (int i = 0; i < s.size(); i++) {
if (s[i] == '-' || isdigit(s[i])) {
// 截取出数字
int sign = 1;
if (s[i] == '-') sign = -1, i++;
int j = i;
while (i < s.size() && isdigit(s[i])) i++;
auto node = new TreeNode(sign * stoi(s.substr(j, i - j)));
// i要挪到数字的最后一位,以便循环i++的时候不错误跳过字符
i--;
// 优先append到栈顶左儿子,如果栈顶已经有了左儿子,则append到右儿子
if (stk.size()) {
if (!stk.top()->left)
stk.top()->left = node;
else
stk.top()->right = node;
}
// 存左链
stk.push(node);
} else if (s[i] == ')')
stk.pop();
}
return stk.size() ? stk.top() : nullptr;
}
};
时空复杂度一样。