L2-004 這是二叉搜索樹嗎?-團體程序設計天梯賽GPLT

題目來源:團體程序設計天梯賽-練習集
題目地址:L2-004 這是二叉搜索樹嗎?

problem

題目大意

給定一個長度爲 nn 的序列,判斷這是否是對一棵二叉搜索樹其鏡像進行前序遍歷的結果。如果是,則在一行中輸出 YES ,然後在下一行輸出該樹後序遍歷的結果,否者直接輸出 NO。

題目分析

1. 預備知識
前序遍歷:先訪問根節點,再遍歷左子樹,最後遍歷右子樹。

後序遍歷:先遍歷左子樹,再遍歷右子樹,最後訪問根節點。
(注意:遍歷子樹的時候也要按照相應的的方式遍歷。)

二叉搜索樹的基本性質(如題目描述所示)

2. 結題要義
首先,我們假設輸入的序列 a[ ]a[\ ] 就是一棵二叉搜索樹進行前序遍歷的結果,llrr 分別爲序列 a[ ]a[\ ] 的左右邊界。

根據前序遍歷的性質,我們可以知道 a[l]a[l] 即爲這棵樹的根節點、 l+1l+1 爲左子樹的左邊界, rr 爲右子樹的右邊界。然後我們定義兩個指針 tltltrtr 分別表示右子樹的左邊界、左子樹的右邊界。(注意哪個對應哪個

初始化 tl=l+1tl = l+1tr=rtr=r,接着根據二叉樹搜索樹的性質 ,tltl 往右移動,找到第一個大於或等於根節點 a[l]a[l] 的節點、trtr往右移動,找到第一個小於根節點 a[l]a[l] 的節點。過程如下圖所示,
1
這樣就確定了序列中根節點、左子樹和右子樹的位置,我們遞歸進行這個這個過程,就可以得到整棵樹的結構,過程如下圖所示:
在這裏插入圖片描述
爲了簡便,我們可以省去建樹的過程,在確定了序列中根節點、左子樹和右子樹的位置後,就直接進行後序遍歷。由確定子樹範圍的過程可得,若這是一顆二叉搜索樹,則必有 tltr=1tl-tr=1 ,要是不滿足這個條件,我們就直接停止遍歷。

訪問根節點時,我們可以將根節點放入 vectorvector 中(vectorvector即爲後序遍歷序列)。最後我們通過判斷 vectorvector 中的元素個數是否等於 nn 來判斷這是否爲二叉搜索樹

如果等於 nn ,就可以輸出 vectorvector ;否則就判斷是否爲鏡像。至於求判斷鏡像的過程也基本和上訴無異,區別在於確定子樹範圍的條件而已。

代碼如下

#include <bits/stdc++.h>

using namespace std;
const int maxn = 1e3 + 10;
int n, flag;
/**
  * a[]用於存儲輸入的前序遍歷序列
  * ans用於存儲後序遍歷的結果
  */
int a[maxn];
vector<int> ans;

/**
  * 後序遍歷這顆二叉樹
  *
  */
void dfs(int l, int r) {
    if (l > r) return ;
    //tl表示右子樹的左邊界,tr表示左子樹的右邊界
    int tl = l + 1, tr = r;
    if (flag) {
        //判斷二叉搜索樹的“鏡像”
        while (tl <= r && a[tl] >= a[l]) tl++;
        while (tr > l && a[tr] < a[l]) tr--;
    } else {
        //判斷二叉搜索樹
        while (tl <= r && a[tl] < a[l]) tl++;
        while (tr > l && a[tr] >= a[l]) tr--;
    }
    //不滿足二叉搜索樹的條件
    if (tl - tr != 1) return ;
    //訪問左子樹
    dfs(l + 1, tr);
    //訪問右子樹
    dfs(tl, r);
    //訪問根節點
    ans.push_back(a[l]);
}


int main()
{
    cin >> n;
    for (int i = 1; i <= n; i++) cin >> a[i];
    //先檢查是不是二叉搜索樹的“鏡像”
    dfs(1, n);
    //如果不滿足,則再檢查是不是二叉搜索樹
    if (ans.size() != n) {
        flag = 1;
        ans.clear();
        dfs(1, n);
    }
    if (ans.size() != n) {
        cout << "NO" << endl;
    } else {
        cout << "YES" << endl;
        for (int i = 0; i < n; i++) {
            cout << ans[i] << (i == n -1 ? '\n' : ' ');
        }
    }
    return 0;
}

如果本文對你有所幫助,記得點個贊哦~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章