題目
輸入一個整數數組,判斷該數組是不是某二叉搜索樹的後序遍歷的結果。如果是則輸出Yes,否則輸出No。假設輸入的數組的任意兩個數字都互不相同。
樣例1
input:7,4,6,5
outpu:false
樣例2
input:2,4,3,6,8,7,5
output:true
解題思路
二叉搜索樹的特點,左子樹中結點的值小於根結點的值,右子樹中結點的值大於根結點的值。
思路1 遞歸
後序遍歷的特點,序列的最後一個元素是當前樹的“根結點”。
所以每次先在最後找到根結點,再根據大小關係劃分左右子樹,遞歸判斷左右子樹是否滿足二叉搜索樹+後序遍歷的兩個特點即可。
思路2 非遞歸
抽象的變換一下形式。把二叉搜索樹的左子樹,當成其右子樹最左邊結點的左子樹,把每次遍歷確定的“根結點”獨立出來爲一個結點。那麼就很容易來通過循環判斷了。
這個後序遍歷序列,最後一個數(即根結點的值)一定比最開始左子樹的大,比最開始右子樹的小,那麼每次遍歷的時候通過二叉搜索樹和後序遍歷序列的特點來對一個下標變量index進行累加,外層循環每次都對index和序列總長度進行比較:
- 當index和總長度不想等時,證明這個序列不是合法的後續遍歷序列;
- 當index和總長度不想等時,證明這個序列是合法的後續遍歷序列,此時把序列長度減去1,即每次把根節點去掉,再進行循環判斷,根基上面提到的兩個特點我們可以確定,這樣的循環是合理的。
白話一點描述上面的非遞歸思路:
- 左子樹結點值一定比右子樹結點值小,因此去掉根結點後,數字分爲left,right兩部分;
- right部分的最後一個數字是右子樹的根結點,他也比左子樹所有值大,因此每次只看右子樹是否符合後序遍歷的條件即可;
- 即使到達了左子樹,左子樹也可以看成是由左、右子樹組成的樹,依然像右子樹那樣處理;
- 對於左子樹的處理就像回到了原問題;
- 對於右子樹,左子樹的所有值都比右子樹的根結點值小,可以暫時把他看成右子樹的左子樹,只需判斷右子樹的右子樹是否符合要求即可。
代碼(Java實現)
思路1 遞歸代碼
/**
* @author : flower48237
* @version: 2020年3月3日 下午3:28:17
*/
public class Solution {
public boolean VerifySquenceOfBST(int []sequence) {
int size = sequence.length;
if(0==size)return false;
while(--size != 0)
{
int i = 0;
while(sequence[i++]<sequence[size]);
while(i < size && sequence[i++]>sequence[size]);
// 第二個while循環的i < size 是爲了防止數組下標越界
if(i<size)
return false;
}
return true;
}
}
思路2 非遞歸代碼
package kd33.VerifySquenceOfBST;
/**
* @author : flower48237
* @version: 2020年3月3日 下午4:57:02
*/
public class Solution2 {
public boolean leaper(int [] sequence, int start, int end) {
// leaper是遞歸函數
if (end <= start)
return true;
int root = sequence[end];
int i = start;
for (; i < end; i++) {
if (sequence[i] > root) {
break;
}
}
int j = i;
for (; j < end; j++) {
if (sequence[j] < root) {
return false;
}
}
return leaper(sequence, start, i - 1) &&leaper(sequence, i, end - 1);
}
public boolean VerifySquenceOfBST(int []sequence) {
int size = sequence.length;
if(size == 0)
return false;
return leaper(sequence, 0, size - 1);
}
}