典型的二叉树问题首先都可以想到用遍历树的方式完成。遍历的方式有DFS和BFS,题中传入的字符串是先序遍历的结果,显然应该用DFS来实现二叉树的还原。
本题的难点在于从字符串获取每个结点对应的深度以及通过深度来找到该节点对应的父亲结点。不论是用递归或者非递归的方法实现,这两部分的代码思想都是一致的。
- 方法一
使用栈来实现非递归的DFS算法,将节点入栈,栈的深度就代表了栈顶元素所代表的的节点对应的深度。因此当栈的长度大于遍历到的节点深度时,表明遍历到的节点的父亲结点不是栈顶元素,需要将栈中元素出栈并通过栈的大小找到对应的父亲节点。
class Solution {
public TreeNode recoverFromPreorder(String S) {
Stack<TreeNode> st = new Stack<>();
TreeNode head= null;
for(int i=0; i<S.length();){
int curLevel = 0;
while(i < S.length() && S.charAt(i)=='-'){
i++;
curLevel++;
}
int start = i;
while(i < S.length() && S.charAt(i)!= '-'){
i++;
}
TreeNode cur = new TreeNode(Integer.parseInt(S.substring(start, i)));
if(st.size()==0){
head = cur;
st.push(cur);
continue;
}
while(st.size()>curLevel){
st.pop();
}
if(!st.isEmpty()){
if(st.peek().left != null){
st.peek().right = cur;
}else{
st.peek().left = cur;
}
st.push(cur);
}
}
return head;
}
}
- 方法二
使用递归的方式,需要定义一个实例域来记录字符串的遍历下标。
树的深度通过在递归函数中传入变量并每次递归+1实现深度的记录,在通过该深度与被遍历的节点的深度进行比较判断遍历到的节点是否是上一层递归中的节点的儿子节点,若是,则优先左子节点后右子节点的顺序进入下一步递归,否则返回上一次递归。
class Solution {
int index;
public TreeNode recoverFromPreorder(String S) {
index=0;
return helper(S, 0);
}
public TreeNode helper(String S, int depth){
if(index >=S.length()){
return null;
}
int curDepth = 0;
int k = index;
while(k<S.length() && S.charAt(k)=='-' ){
curDepth++;
k++;
}
if (curDepth != depth) return null;
index = k;
while(k<S.length() && S.charAt(k) != '-'){
k++;
}
int val = Integer.parseInt(S.substring(index, k));
index = k;
TreeNode cur = new TreeNode(val);
cur.left = helper(S, depth+1);
cur.right = helper(S, depth+1);
return cur;
}
}