代碼原作者的代碼利用了遞歸思想,寫得很好。鏈接在此https://cloud.tencent.com/developer/article/1401290
由於本人腦子笨,有些細節地方轉不過來(其實以前碰到這種情況也是要想好久)。比如本題代碼中的參數問題:
public class Solution {
private TreeNode rebuildTree(int[] pre, int preStart, int preEnd, int[] in, int inStart, int inEnd) {
if(preStart > preEnd | inStart > inEnd)
return null;
// 根節點
TreeNode root = new TreeNode(pre[preStart]);
// 尋找根節點在中序序列的位置
for (int i = inStart; i <= inEnd; i++) {
if (in[i] == pre[preStart]) {
// 可以計算出中序序列的左右子樹序列爲:左:inStart~i -1,右:i+1~inEnd。
// 前序序列的左右子樹:左:preStart+1~preStart+i-inStart,右:preStart+i-inStart+1~preEnd
root.left = rebuildTree(pre,preStart+1, preStart+i-inStart,in, inStart, i - 1);
root.right = rebuildTree(pre,preStart+i-inStart+1, preEnd, in, i+1, inEnd);
}
}
return root;
}
public TreeNode reConstructBinaryTree(int [] pre,int [] in) {
TreeNode root;
root = rebuildTree(pre, 0, pre.length - 1, in, 0, in.length - 1);
return root;
}
}
問題就在以下兩句
root.left = rebuildTree(pre,preStart+1, preStart+i-inStart,in, inStart, i - 1);
root.right = rebuildTree(pre,preStart+i-inStart+1, preEnd, in, i+1, inEnd);
在preStart+i-inStart中爲什麼要減去inStart呢?不減不行嗎?反正inStart剛好是0啊?後來自己走了幾次代碼,遞歸調用函數後發現inStart雖然在左邊,但不會一直是0。(真是菜啊)
如圖所示,劃分後的中序序列的左半部分是要用來構建根節點的左子樹的,這一部分的長度剛好是length=i-inStart,所以在前序序列中,左子樹的序列截取範圍就是從preStart+1到preStart+length,即preStart+i-inStart,然後右子樹的前序序列範圍就是preStart+i-inStart+1到preEnd了。
其實以前做題也碰到過類似的情況,某個參數傳進去的時候加1或者減1就對了,差了個1就不行。大一的時候剛學冒泡排序,有的地方已經不用遍歷到結尾了,傳參j<n-i,還不知道爲啥,關鍵也在沒弄明白i的改變會有什麼影響。二叉樹這一題,也犯了類似的錯誤,本應該宏觀一點切割序列,一段一段來看,卻只切割了一次,使用了類似暴力的方式從preStart往右邊數了幾個數字,剛好有i個,於是覺得preStart+i沒毛病,錯就錯在第一遍切割inStart是剛好是0,所以沒影響。preStart的偏移量應該剛好是左子樹序列的長度纔對,想到了“一段長度”這個概念會更早發現錯誤。