給定一個整數數組,判斷該數組是否為某二叉搜索樹的後序遍歷結果。若是輸出 Yes,否則輸出 No。假設數組中任意兩數互不相同。
n(1 ≤ n ≤ 10000),第二行 n 個整數Yes 或 No輸入: 7 5 7 6 9 11 10 8 4 7 4 6 5 輸出: Yes No
二叉搜索樹(BST)性質:左子樹所有節點 < 根節點 < 右子樹所有節點。
後序遍歷順序:左子樹 → 右子樹 → 根節點。
因此,後序序列的最後一個元素必是根節點。剩餘序列可分為兩段:
前段(左子樹)全部 < 根值,後段(右子樹)全部 > 根值。遞歸驗證即可。
root = seq[j] 作為根< root 的位置 flag,此前應全為 > root(右子樹)flag 向左驗證是否全為 < root(左子樹)0[i, flag] 和右子序列 [flag+1, j-1]BST 可能只有左子樹或只有右子樹(非滿二叉樹)。例如序列 1 2 3(只有右子樹)或 3 2 1(只有左子樹)均合法。代碼中通過以下判斷處理:
if (test[i] > test[j] || test[j-1] < test[j]) {
// 單邊子樹:全部大於根 或 全部小於根
return isPost(i, j-1);
}
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
int test[10005] = {0};
int isPost(int i, int j);
int main() {
int n;
while (scanf("%d", &n) != EOF) {
for (int i = 0; i < n; i++) scanf("%d", &test[i]);
if (isPost(0, n-1)) printf("Yes\n");
else printf("No\n");
}
return 0;
}
int isPost(int i, int j) {
if (i == j) return 1; // 單節點
int k = j - 1;
// 從右向左找右子樹邊界(全 > root)
while (k >= i && test[k] > test[j]) k--;
int flag = k;
// 繼續向左驗證左子樹(全 < root)
while (k >= i && test[k] < test[j]) k--;
if (k == i - 1) { // 完美分割
// 單邊子樹優化
if (test[i] > test[j] || test[j-1] < test[j]) {
return isPost(i, j-1);
} else {
return isPost(i, flag) && isPost(flag+1, j-1);
}
} else {
return 0; // 存在交叉,非BST後序
}
}
/**************************************************************
Problem: 1367
Result: Accepted
Time: 10 ms
Memory: 952 kb
**************************************************************/