L2-004 這是二叉搜尋樹嗎?
L2-004 這是二叉搜尋樹嗎?
https://pintia.cn/problem-sets/994805046380707840/problems/994805070971912192
題意
一棵二叉搜尋樹可被遞迴地定義為具有下列性質的二叉樹:對於任一結點,其左子樹中所有結點的鍵值小於該結點的鍵值;其右子樹中所有結點的鍵值大於等於該結點的鍵值;其左右子樹都是二叉搜尋樹。所謂二叉搜尋樹的“映象”,即將所有結點的左右子樹對換位置後所得到的樹。給定一個整數鍵值序列,現請你編寫程式,判斷這是否是對一棵二叉搜尋樹或其映象進行前序遍歷的結果。
輸入
輸入的第一行給出正整數 N(≤1000)。隨後一行給出 N 個整數鍵值,其間以空格分隔。
輸出
如果輸入序列是對一棵二叉搜尋樹或其映象進行前序遍歷的結果,則首先在一行中輸出 YES
,然後在下一行輸出該樹後序遍歷的結果。數字間有 1 個空格,一行的首尾不得有多餘空格。若答案是否,則輸出 NO
。
樣例輸入
1)
7
8 6 5 7 10 8 11
2)
7
8 10 11 8 6 7 5
3)
7
8 6 8 5 10 9 11
樣例輸出
1)
YES
5 7 6 8 11 10 8
2)
YES
11 8 10 7 5 6 8
3)
NO
分析
使用前序遍歷和中序遍歷構造樹,如果一顆樹是而二叉搜尋樹,則它的中序遍歷是非遞減的,如果一棵樹是二叉搜尋樹的映象樹,那麼它的中序遍歷是非遞增的,我們可以通過這個性質以及題目給出的前序遍歷求出樹的中序遍歷,先構造二叉搜尋樹,如果失敗的話再進行構造二叉搜尋樹的映象樹,如果還是失敗就輸出“NO”,否則輸出“YES”和構造成的樹的中序遍歷。
一棵二叉搜尋樹可被遞迴地定義為具有下列性質的二叉樹:對於任一結點,其左子樹中所有結點的鍵值小於該結點的鍵值;其右子樹中所有結點的鍵值大於等於該結點的鍵值;其左右子樹都是二叉搜尋樹。那麼二叉搜尋樹的映象樹的可這樣定義:對於任一結點,其左子樹中所有結點的鍵值大於等於該結點的鍵值;其右子樹中所有結點的鍵值小於該結點的鍵值;其左右子樹都是二叉搜尋樹的映象樹。
由於題目給出的結點鍵值可能是一樣的,因此在構造二叉搜尋樹的映象樹時,必須按照從後往前的順序在中序遍歷陣列中找和根節點,這樣和根節點鍵值相同的重複結點就會稱為左子樹,這樣才符合二叉搜尋樹的映象樹,如果不這樣的話,樣例二不會通過。
C++程式
#include<iostream>
#include<algorithm>
using namespace std;
const int N=1005;
//結點
struct Node{
int val;
Node *l,*r;
Node(int val):val(val),l(NULL),r(NULL){}
};
//後序遍歷
bool flag;
void post(Node *x)
{
if(x)
{
post(x->l);
post(x->r);
if(flag) printf(" ");
printf("%d",x->val);
flag=true;
}
}
int pre[N],in[N];//前序遍歷和中序遍歷結果
//是否能構造一棵二叉樹
bool legal;
//根據前序遍歷和中序遍歷構造二叉搜尋樹
// l,r表示pre的區間,a,b表示in的區間,dir表示從前往後找,還是從後往前找
Node* build(int l,int r,int a,int b,bool dir)
{
if(legal&&l<=r)
{
int rt=pre[l];
int mid;
if(dir)//從前往後找(用於構造二叉搜尋樹)
for(mid=a;mid<=b&&in[mid]!=rt;mid++);
else//從後往前找(用於構造二叉搜尋樹進行映象操作後的樹)
for(mid=b;mid>=a&&in[mid]!=rt;mid--);
if((dir&&mid>b)||(!dir&&mid<a))//構造失敗
{
legal=false;
return NULL;
}
Node *node=new Node(rt);
node->l=build(l+1,mid-a+l,a,mid-1,dir);
node->r=build(mid-a+l+1,r,mid+1,b,dir);
return node;
}
return NULL;
}
//銷燬樹
void destroy(Node *x)
{
if(x)
{
destroy(x->l);
destroy(x->r);
delete x;
x=NULL;
}
}
int main()
{
int n;
scanf("%d",&n);
for(int i=0;i<n;i++)
{
scanf("%d",&pre[i]);
in[i]=pre[i];
}
//二叉搜尋樹的中序遍歷是非遞減的 ,利用前序遍歷和中序遍歷構造二叉樹
sort(in,in+n);
legal=true;
Node *root=build(0,n-1,0,n-1,true);
//如果構造失敗,說明不是二叉搜尋樹,進一步判斷它是否為二叉樹進行鏡面操作後的樹
if(!legal)
{
destroy(root);//刪除構造失敗的樹
reverse(in,in+n);//中序遍歷是非第增的
legal=true;
root=build(0,n-1,0,n-1,false);
}
if(legal)//構造二叉搜尋樹或二叉搜尋樹映象後的樹成功
{
printf("YES\n");
post(root);
}
else//失敗
printf("NO\n");
destroy(root);
return 0;
}
相關文章
- 二叉搜尋樹
- 從二分搜尋到二叉搜尋樹
- Day20 | 654.最大二叉樹 、 617.合併二叉樹 、 700.二叉搜尋樹中的搜尋 98.驗證二叉搜尋樹二叉樹
- 程式碼隨想錄day18 || 530 二叉搜尋樹最小差,501 二叉搜尋樹眾數,236 二叉搜尋樹最近公共祖先
- 二叉搜尋樹的操作集
- 二叉搜尋樹的結構
- javascript實現二叉搜尋樹JavaScript
- 有序表和搜尋二叉樹二叉樹
- js實現完全排序二叉樹、二叉搜尋樹JS排序二叉樹
- 二叉搜尋樹和二叉樹的最近公共祖先二叉樹
- Leetcode 700. 二叉搜尋樹中的搜尋(DAY 2)LeetCode
- 資料結構中的樹(二叉樹、二叉搜尋樹、AVL樹)資料結構二叉樹
- JavaScript 二叉搜尋樹以及實現翻轉二叉樹JavaScript二叉樹
- 二叉搜尋樹的python實現Python
- 演算法篇 - 二叉搜尋樹演算法
- 96. 不同的二叉搜尋樹
- 【資料結構】二叉搜尋樹!!!資料結構
- 手寫AVL平衡二叉搜尋樹
- 資料結構-二叉搜尋樹資料結構
- leetcode 700. 二叉搜尋樹中的搜尋 思考分析LeetCode
- 滿二叉樹、完全二叉樹、平衡二叉樹、二叉搜尋樹(二叉查詢樹)和最優二叉樹二叉樹
- python 二叉樹深度優先搜尋和廣度優先搜尋Python二叉樹
- 資料結構之「二叉搜尋樹」資料結構
- LeetCode 95 | 構造出所有二叉搜尋樹LeetCode
- [Python手撕]不同的二叉搜尋樹Python
- [Python手撕]判斷二叉搜尋樹Python
- LeetCode98. 驗證二叉搜尋樹LeetCode
- LeetCode-098-驗證二叉搜尋樹LeetCode
- LeetCode-099-恢復二叉搜尋樹LeetCode
- 二叉搜尋樹如何刪除節點
- 【LeetCode】98. 驗證二叉搜尋樹LeetCode
- LeetCode-096-不同的二叉搜尋樹LeetCode
- LeetCode-173-二叉搜尋樹迭代器LeetCode
- 資料結構☞二叉搜尋樹BST資料結構
- 一文搞定二叉排序(搜尋)樹排序
- 判斷序列是否是二叉搜尋樹的後續遍歷
- 程式碼隨想錄演算法訓練營第第20天 | 654.最大二叉樹 、617.合併二叉樹 、700.二叉搜尋樹中的搜尋、98.驗證二叉搜尋樹演算法二叉樹
- 程式碼隨想錄 第20天 20的總結沒看 | 654.最大二叉樹 ● 617.合併二叉樹 ● 700.二叉搜尋樹中的搜尋 ● 98.驗證二叉搜尋樹二叉樹