(程序設計天梯賽)L2-004 這是二叉搜索樹嗎? (25 分)


題目鏈接

L2-004 這是二叉搜索樹嗎? (25 分)
一棵二叉搜索樹可被遞歸地定義為具有下列性質的二叉樹:對於任一結點,

其左子樹中所有結點的鍵值小於該結點的鍵值;
其右子樹中所有結點的鍵值大於等於該結點的鍵值;
其左右子樹都是二叉搜索樹。
所謂二叉搜索樹的“鏡像”,即將所有結點的左右子樹對換位置后所得到的樹。

給定一個整數鍵值序列,現請你編寫程序,判斷這是否是對一棵二叉搜索樹或其鏡像進行前序遍歷的結果。

輸入格式:

輸入的第一行給出正整數 N(≤1000)。隨后一行給出 N 個整數鍵值,其間以空格分隔。

輸出格式:

如果輸入序列是對一棵二叉搜索樹或其鏡像進行前序遍歷的結果,則首先在一行中輸出 YES ,然后在下一行輸出該樹后序遍歷的結果。數字間有 1 個空格,一行的首尾不得有多余空格。若答案是否,則輸出 NO。

輸入樣例 1:

7
8 6 5 7 10 8 11

輸出樣例 1:

YES
5 7 6 8 11 10 8

輸入樣例 2:

7
8 10 11 8 6 7 5

輸出樣例 2:

YES
11 8 10 7 5 6 8

輸入樣例 3:

7
8 6 8 5 10 9 11

輸出樣例 3:

NO

這題用遞歸的方法嘗試進行建樹,如果出現相駁就能返回false,文中有注釋幫助理解,如有問題可直接評論。

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.StreamTokenizer;
import java.util.Scanner;

public class Main {
	static StreamTokenizer st = new StreamTokenizer(new BufferedInputStream(System.in));

	static int out[] = new int[1005];// 后序遍歷結果
	static int next;

	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int N = nextNum();
		next = N;
		if (N == 0) {
			System.out.println("YES");
			return;
		}
		int arr[] = new int[1005];
		for (int i = 0; i < N; i++) {
			arr[i] = nextNum();
		}
		if (build(arr, 0, N, true, arr[0])) {
			System.out.println("YES");
			System.out.print(out[0]);
			for (int i = 1; i < N; i++) {
				System.out.print(" " + out[i]);
			}
		} else {
			next = N;
			if (buildjx(arr, 0, N, true, arr[0])) {
				System.out.println("YES");
				System.out.print(out[0]);
				for (int i = 1; i < N; i++) {
					System.out.print(" " + out[i]);
				}
			} else {
				System.out.println("NO");

			}
		}
	}

	/** * 判斷能否代表二叉排序樹 * @param arr 二叉樹組 * @param l 左起始 * @param r 有終點 * @param lr 代表該樹是左節點還是右節點,true為左節點 * @param preRoot 為該樹父節點 * @return 判斷結果 */
	private static boolean build(int arr[], int l, int r, boolean lr, int preRoot) {
		if (l >= r) {
			return true;
		}
		int root = arr[l];
		out[--next] = root;// 存儲其根
		if (lr) {
			for (int i = l + 1; i < r; i++) {
				if (root <= arr[i]) {// 當出現大於等於該根的時候,可認為剩余的為右子樹
					// 后根遍歷中有子樹根節點后出所以先遞歸右節點,再遞歸左節點
					return build(arr, i, r, false, root) && build(arr, l + 1, i, true, root);
				}
			}
		} else {
			for (int i = l + 1; i < r; i++) {// 由於右子樹都大於等於根,出現小於的時候,必然不能代表二叉樹
				if (arr[i] < preRoot) {
					return false;
				}
			}
			for (int i = l + 1; i < r; i++) {
				if (root <= arr[i]) {
					return build(arr, i, r, false, root) && build(arr, l + 1, i, true, root);
				}
			}
		}
		return build(arr, l + 1, r, true, root);
	}

	/** * 判斷能否代表二叉排序樹 和判斷是否代表二叉排序樹基本相同,只是變了下符號 * @param arr 二叉樹組 * @param l 左起始 * @param r 有終點 * @param lr 代表該樹是左節點還是右節點,true為左節點 * @param preRoot 為該樹父節點 * @return 判斷結果 */
	private static boolean buildjx(int arr[], int l, int r, boolean lr, int preRoot) {
		if (l >= r) {
			return true;
		}
		int root = arr[l];
		out[--next] = root;
		if (lr) {
			for (int i = l + 1; i < r; i++) {
				if (root > arr[i]) {
					return buildjx(arr, i, r, false, root) && buildjx(arr, l + 1, i, true, root);
				}
			}
		} else {
			for (int i = l + 1; i < r; i++) {
				if (arr[i] > preRoot) {
					return false;
				}
			}
			for (int i = l + 1; i < r; i++) {
				if (root > arr[i]) {
					return buildjx(arr, i, r, false, root) && buildjx(arr, l + 1, i, true, root);
				}
			}
		}
		return buildjx(arr, l + 1, r, true, root);
	}
	private static int nextNum() {
		try {
			st.nextToken();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return (int) st.nval;

	}
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM