PAT 1043 Is It a Binary Search Tree[二叉樹][難]

1043 Is It a Binary Search Tree(25 分)

A Binary Search Tree (BST) is recursively defined as a binary tree which has the following properties:html

  • The left subtree of a node contains only nodes with keys less than the node's key.
  • The right subtree of a node contains only nodes with keys greater than or equal to the node's key.
  • Both the left and right subtrees must also be binary search trees.

If we swap the left and right subtrees of every node, then the resulting tree is called the Mirror Image of a BST.node

Now given a sequence of integer keys, you are supposed to tell if it is the preorder traversal sequence of a BST or the mirror image of a BST.數組

Input Specification:

Each input file contains one test case. For each case, the first line contains a positive integer N (1000). Then Ninteger keys are given in the next line. All the numbers in a line are separated by a space.less

Output Specification:

For each test case, first print in a line YES if the sequence is the preorder traversal sequence of a BST or the mirror image of a BST, or NO if not. Then if the answer is YES, print in the next line the postorder traversal sequence of that tree. All the numbers in a line must be separated by a space, and there must be no extra space at the end of the line.post

Sample Input 1:

7
8 6 5 7 10 8 11

Sample Output 1:

YES
5 7 6 8 11 10 8

Sample Input 2:

7
8 10 11 8 6 7 5

Sample Output 2:

YES
11 8 10 7 5 6 8

Sample Input 3:

7
8 6 8 5 10 9 11

Sample Output 3:

NO

 題目大意:如初一系列數,若是它是給出一棵二叉搜索樹的前根遍歷或者是它的左右子數反轉的二叉樹的前根便利(關鍵字會重複出現), 那麼就輸出Yes,而且輸出這棵二叉樹的後根遍歷,若是不是輸出No。學習

//創建一棵樹,存儲,使用數組存儲。spa

代碼來自:https://www.liuchuo.net/archives/2153.net

#include <cstdio>
#include <vector>
using namespace std;
bool isMirror;
vector<int> pre, post;
void getpost(int root, int tail) {
    if(root > tail) return ;
    int i = root + 1, j = tail;
    if(!isMirror) {
        while(i <= tail && pre[root] > pre[i]) i++;
        //這個i一直循環到右子樹的根節點,由於root的右子樹是>pre[root]的。
        while(j > root && pre[root] <= pre[j]) j--;
        //這個是找到左子樹前序遍歷的最後一個節點。
    } else {
        while(i <= tail && pre[root] <= pre[i]) i++;
        while(j > root && pre[root] > pre[j]) j--;
    }
    if(i - j != 1) return ;
    getpost(root + 1, j);//遍歷左子樹,
    getpost(i, tail);//遍歷右子樹
    post.push_back(pre[root]);//後根遍歷放進來。
    //當時葉節點的時候,會在入口處的if直接return了。
}
int main() {
    int n;
    scanf("%d", &n);
    pre.resize(n);
    for(int i = 0; i < n; i++)
        scanf("%d", &pre[i]);//輸入前序。
    getpost(0, n - 1);//獲取後序,
    if(post.size() != n) {
        isMirror = true;
        post.clear();
        getpost(0, n - 1);
    }
    if(post.size() == n) {//若是是正常搜索二叉樹的話,應該是=n的,有這麼個規律在的。
        printf("YES\n%d", post[0]);//0直接在這裏輸出。
        for(int i = 1; i < n; i++)
            printf(" %d", post[i]);
    } else {
        printf("NO");
    }
    return 0;
}

 

 //柳神的應該是能AC的代碼中最精簡的了,不用建樹,厲害,以前也見到過這樣的題目,應該加深一下,學習了。指針

 //正常來講的思路就是,建樹,因此參考瞭如下代碼,也十分整潔:https://www.nowcoder.com/questionTerminal/8bcd661314744321b55dce1c1bfa8c54code

 

//全是套路==
#include <cstdio>
#include <vector>
using namespace std;
struct Node{
    int value;
    Node *left, *right;//用的是指針喲。
};

void Insert(Node* &root, int data){//今天本身建樹不成功才發現, 原來這位大佬傳的是指針的引用,只傳指針是不行的,學習了!2018-9-7
    if(root == NULL){
        root = new Node;//新指向一個節點。
        root -> value = data;
        root -> left = NULL;
        root -> right = NULL;
        return;
    }
    if(data < root->value) Insert(root->left, data);
    else Insert(root->right, data);//由此看來>=root都是放在右子樹的。
}

void PreOrder(Node* root, vector<int>& v){
    if(root == NULL) return;
    v.push_back(root->value);//先訪問根節點,再左右子樹。
    PreOrder(root->left, v);
    PreOrder(root->right, v);
}

void PreMirrorOrder(Node* root, vector<int>& v){
    if(root == NULL) return;
    v.push_back(root->value);
    PreMirrorOrder(root->right, v);
    PreMirrorOrder(root->left, v);
}

void PostOrder(Node* root, vector<int>& v){//注意這裏傳了引用,其實也能夠將其設置爲全局變量。
    if(root == NULL) return;
    PostOrder(root->left, v);
    PostOrder(root->right, v);
    v.push_back(root->value);
}

void PostMirrorOrder(Node* root, vector<int>& v){
    if(root == NULL) return;
    PostMirrorOrder(root->right, v);//既然右邊小,那麼就先訪問右邊
    PostMirrorOrder(root->left, v);//再訪問左邊,造成的是和正常地是同樣的序列。
    v.push_back(root->value);
}

int main(){
    int n;
    Node* s = NULL;
    scanf("%d", &n);
    vector<int> num, pre, preM, post, postM;
    for(int i=0; i<n; i++){
        int data;
        scanf("%d", &data);
        num.push_back(data);
        Insert(s, data);//使用指針傳遞,第一次就不是null了.
        //此處建樹最終建成的是一個標準的搜索二叉樹。
    }
    PreOrder(s, pre);
    if(num == pre){//判斷兩個向量是否相等,直接判斷就能夠了。
        PostOrder(s, post);
        printf("YES\n");
        for(unsigned int i=0; i<post.size(); i++){
            printf("%d", post[i]);
            if(i < post.size()-1) printf(" ");
        }
    }
    else{
        PreMirrorOrder(s, preM);
        if(num == preM){
            PostMirrorOrder(s, postM);
            printf("YES\n");
            for(unsigned int i=0; i<postM.size(); i++){
                printf("%d", postM[i]);
                if(i < postM.size()-1) printf(" ");
            }
        }
        else printf("NO\n");
    }
    return 0;
}

 

//這個感受是正常地思路。 

1.首先按輸入序列,建成一個標準的二叉搜索樹,而且保存輸入序列爲num(題目中給的也是前序遍歷)。

2.而後對其進行前序遍歷,獲得結果pre;

3.此時將pre與輸入序列對比,若是=,那麼就是正常的二叉搜索樹

4.不然就多是鏡像或者徹底不是二者。

5.此時對二叉樹進行鏡像前序遍歷(由於鏡像也就是將左右子樹反轉,那麼此時訪問根節點後,再訪問建好的二叉樹的右子樹不就至關於對鏡像進行前序遍歷了嗎)

6.獲得的結果是preM,若是和num相同那麼就是鏡像的,而後對其進行後序鏡像遍歷輸出

7.不然不是兩者,輸出no.

//厲害,學習了,建樹的過程,以及前序和後序遍歷,都明白了,多複習! 

相關文章
相關標籤/搜索