33. 二叉搜索树的后序遍历序列【难】


comments: true
difficulty: 中等
edit_url: https://github.com/doocs/leetcode/edit/main/lcof/%E9%9D%A2%E8%AF%95%E9%A2%9833.%20%E4%BA%8C%E5%8F%89%E6%90%9C%E7%B4%A2%E6%A0%91%E7%9A%84%E5%90%8E%E5%BA%8F%E9%81%8D%E5%8E%86%E5%BA%8F%E5%88%97/README.md

面试题 33. 二叉搜索树的后序遍历序列

题目描述

输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历结果。如果是则返回 true,否则返回 false。假设输入的数组的任意两个数字都互不相同。

 

参考以下这颗二叉搜索树:

     5
    / \
   2   6
  / \
 1   3

示例 1:

输入: [1,6,3,2,5]
输出: false

示例 2:

输入: [1,3,2,6,5]
输出: true

 

提示:

  1. 数组长度 <= 1000

解法

方法一:递归

后序遍历的最后一个元素为根节点,根据二叉搜索树的性质,根节点左边的元素都小于根节点,根节点右边的元素都大于根节点。因此,我们找到第一个大于根节点的位置 i i i,那么 i i i 右边的元素都应该大于根节点,否则返回 false。然后递归判断左右子树。

时间复杂度 O ( n 2 ) O(n^2) O(n2),空间复杂度 O ( n ) O(n) O(n)。其中 n n n 为数组长度。

Python3

【LeetCode力扣刷题 | 剑指Offer 33. 二叉搜索树的后序遍历序列(思路讲解及Python3代码实现)程序员面试手撕代码必刷题库】 https://www.bilibili.com/video/BV1FK4y1j73k/?share_source=copy_web&vd_source=ed4a51d52f6e5c9a2cb7def6fa64ad6a

class Solution:
    def verifyPostorder(self, postorder: List[int]) -> bool:
        def dfs(l, r):
            if l >= r:return True
            
            v = postorder[r] #根节点值
            
            i = l
            while i < r and postorder[i] < v:
                i += 1 #左子树遍历,确保都比根节点小【退出时,i位置为第一个右子树元素的位置】  
            
           	j=i
            if any(x < v for x in postorder[j:r]):
                return False #右子树遍历,并检验是否都比 都比根节点大
                
            return dfs(l, j - 1) and dfs(j, r - 1) #递归左右子树

        return dfs(0, len(postorder) - 1)
Java
class Solution {
    private int[] postorder;

    public boolean verifyPostorder(int[] postorder) {
        this.postorder = postorder;
        return dfs(0, postorder.length - 1);
    }

    private boolean dfs(int l, int r) {
        if (l >= r) {
            return true;
        }
        int v = postorder[r];
        int i = l;
        while (i < r && postorder[i] < v) {
            ++i;
        }
        for (int j = i; j < r; ++j) {
            if (postorder[j] < v) {
                return false;
            }
        }
        return dfs(l, i - 1) && dfs(i, r - 1);
    }
}
C++
class Solution {
public:
    bool verifyPostorder(vector<int>& postorder) {
        function<bool(int, int)> dfs = [&](int l, int r) -> bool {
            if (l >= r) {
                return true;
            }
            int v = postorder[r];
            int i = l;
            while (i < r && postorder[i] < v) {
                ++i;
            }
            for (int j = i; j < r; ++j) {
                if (postorder[j] < v) {
                    return false;
                }
            }
            return dfs(l, i - 1) && dfs(i, r - 1);
        };
        return dfs(0, postorder.size() - 1);
    }
};
Go
func verifyPostorder(postorder []int) bool {
	var dfs func(l, r int) bool
	dfs = func(l, r int) bool {
		if l >= r {
			return true
		}
		v := postorder[r]
		i := l
		for i < r && postorder[i] < v {
			i++
		}
		for j := i; j < r; j++ {
			if postorder[j] < v {
				return false
			}
		}
		return dfs(l, i-1) && dfs(i, r-1)
	}
	return dfs(0, len(postorder)-1)
}
TypeScript
function verifyPostorder(postorder: number[]): boolean {
    const dfs = (l: number, r: number): boolean => {
        if (l >= r) {
            return true;
        }
        const v = postorder[r];
        let i = l;
        while (i < r && postorder[i] < v) {
            ++i;
        }
        for (let j = i; j < r; ++j) {
            if (postorder[j] < v) {
                return false;
            }
        }
        return dfs(l, i - 1) && dfs(i, r - 1);
    };
    return dfs(0, postorder.length - 1);
}
Rust
impl Solution {
    fn dfs(start: usize, end: usize, max_val: i32, postorder: &Vec<i32>) -> bool {
        if start >= end {
            return true;
        }
        let root_val = postorder[end - 1];
        for i in (start..end).rev() {
            let val = postorder[i];
            if val > max_val {
                return false;
            }
            if val < root_val {
                return (Self::dfs(start, i, root_val, postorder)
                    && Self::dfs(i + 1, end - 1, max_val, postorder));
            }
        }
        Self::dfs(start, end - 1, max_val, postorder)
    }

    pub fn verify_postorder(postorder: Vec<i32>) -> bool {
        Self::dfs(0, postorder.len(), i32::MAX, &postorder)
    }
}
JavaScript
/**
 * @param {number[]} postorder
 * @return {boolean}
 */
var verifyPostorder = function (postorder) {
    const dfs = (l, r) => {
        if (l >= r) {
            return true;
        }
        const v = postorder[r];
        let i = l;
        while (i < r && postorder[i] < v) {
            ++i;
        }
        for (let j = i; j < r; ++j) {
            if (postorder[j] < v) {
                return false;
            }
        }
        return dfs(l, i - 1) && dfs(i, r - 1);
    };
    return dfs(0, postorder.length - 1);
};
C#
public class Solution {
    private int[] postorder;

    public bool VerifyPostorder(int[] postorder) {
        this.postorder = postorder;
        return dfs(0, postorder.Length - 1);
    }

    private bool dfs(int l, int r) {
        if (l >= r) {
            return true;
        }
        int v = postorder[r];
        int i = l;
        while (i < r && postorder[i] < v) {
            ++i;
        }
        for (int j = i; j < r; ++j) {
            if (postorder[j] < v) {
                return false;
            }
        }
        return dfs(l, i - 1) && dfs(i, r - 1);
    }
}
Swift
class Solution {
    private var postorder: [Int] = []

    func verifyPostorder(_ postorder: [Int]) -> Bool {
        self.postorder = postorder
        return dfs(0, postorder.count - 1)
    }

    private func dfs(_ l: Int, _ r: Int) -> Bool {
        if l >= r {
            return true
        }
        let rootValue = postorder[r]
        var i = l
        while i < r && postorder[i] < rootValue {
            i += 1
        }
        for j in i..<r {
            if postorder[j] < rootValue {
                return false
            }
        }
        return dfs(l, i - 1) && dfs(i, r - 1)
    }
}

方法二:单调栈【难】

后序遍历的顺序为“左、右、根”,如果我们从右往左遍历数组,那么顺序就变成“根、右、左”,根据二叉搜索树的性质,右子树所有节点值均大于根节点值。

因此,从右往左遍历数组,就是从根节点往右子树走,此时值逐渐变大,直到遇到一个递减的节点,此时的节点应该属于左子树根节点。我们找到该节点,那么此后其它节点【左子树】都应该小于该父节点,否则返回 false。然后继续遍历,直到遍历完整个数组。

此过程,我们借助栈来实现,具体步骤如下:

我们首先初始化一个无穷大的父节点值 m x mx mx,然后初始化一个空栈。

接下来,我们从右往左遍历数组,对于每个遍历到的元素 x x x

-如果 x x x 大于 m x mx mx,说明当前节点不满足二叉搜索树的性质【即左子树的节点 > 左子树根节点】,返回 false
- 否则,如果当前栈不为空,且栈顶元素大于 x x x【根->右,维护递减栈】,说明当前节点为左子树节点,我们循环将栈顶元素出栈并赋值给 m x mx mx,直到栈为空或者栈顶元素小于等于 x x x,然后将 x x x 入栈。

遍历结束后,返回 true

时间复杂度 O ( n ) O(n) O(n),空间复杂度 O ( n ) O(n) O(n)。其中 n n n 为数组长度。

【单调栈【基础算法精讲 26】】 https://www.bilibili.com/video/BV1VN411J7S7/?share_source=copy_web&vd_source=ed4a51d52f6e5c9a2cb7def6fa64ad6a
【o(n)找下一个更大元素】

Python3
class Solution:
    def verifyPostorder(self, postorder: List[int]) -> bool:
        mx = inf
        stk = []
        for x in postorder[::-1]:
            #2)遇到左子树的节点 > 左子树根节点mx【不满足递减栈条件退出时的元素】,返回 `false`
            if x > mx:
                return False
            #1)根->右:维护单调递减栈
            while stk and stk[-1] > x:
                mx = stk.pop()
            stk.append(x)
        return True
Java
class Solution {
    public boolean verifyPostorder(int[] postorder) {
        int mx = 1 << 30;
        Deque<Integer> stk = new ArrayDeque<>();
        for (int i = postorder.length - 1; i >= 0; --i) {
            int x = postorder[i];
            if (x > mx) {
                return false;
            }
            while (!stk.isEmpty() && stk.peek() > x) {
                mx = stk.pop();
            }
            stk.push(x);
        }
        return true;
    }
}
C++
class Solution {
public:
    bool verifyPostorder(vector<int>& postorder) {
        stack<int> stk;
        int mx = 1 << 30;
        reverse(postorder.begin(), postorder.end());
        for (int& x : postorder) {
            if (x > mx) {
                return false;
            }
            while (!stk.empty() && stk.top() > x) {
                mx = stk.top();
                stk.pop();
            }
            stk.push(x);
        }
        return true;
    }
};
Go
func verifyPostorder(postorder []int) bool {
	mx := 1 << 30
	stk := []int{}
	for i := len(postorder) - 1; i >= 0; i-- {
		x := postorder[i]
		if x > mx {
			return false
		}
		for len(stk) > 0 && stk[len(stk)-1] > x {
			mx = stk[len(stk)-1]
			stk = stk[:len(stk)-1]
		}
		stk = append(stk, x)
	}
	return true
}
TypeScript
function verifyPostorder(postorder: number[]): boolean {
    let mx = 1 << 30;
    const stk: number[] = [];
    for (let i = postorder.length - 1; i >= 0; --i) {
        const x = postorder[i];
        if (x > mx) {
            return false;
        }
        while (stk.length && stk[stk.length - 1] > x) {
            mx = stk.pop();
        }
        stk.push(x);
    }
    return true;
}
JavaScript
/**
 * @param {number[]} postorder
 * @return {boolean}
 */
var verifyPostorder = function (postorder) {
    let mx = 1 << 30;
    const stk = [];
    for (let i = postorder.length - 1; i >= 0; --i) {
        const x = postorder[i];
        if (x > mx) {
            return false;
        }
        while (stk.length && stk[stk.length - 1] > x) {
            mx = stk.pop();
        }
        stk.push(x);
    }
    return true;
};
  • 22
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
对于这个问题,我们可以使用队列和分治法来求解二叉搜索树的层序遍历。具体的实现方法如下: 1. 首先,根据后序遍历的定义,可以知道二叉搜索树的根节点是序列的最后一个元素。 2. 然后,使用分治法将序列划分为两个部分,即左子树和右子树。可以找到第一个比根节点小的元素,将其之前的部分定义为左子树的后序遍历,之后的部分定义为右子树的后序遍历。 3. 对于左右子树,分别重复上述过程,递归求解左右子树的层序遍历。 4. 最后,将左右子树的层序遍历按照层次合并起来,即可得到整棵二叉搜索树的层序遍历。 下面是具体的实现代码: ```python def postorder_to_levelorder(postorder): if not postorder: return [] root = postorder[-1] mid = bisect.bisect_left(postorder, root) left_postorder = postorder[:mid] right_postorder = postorder[mid:-1] left_levelorder = postorder_to_levelorder(left_postorder) right_levelorder = postorder_to_levelorder(right_postorder) levelorder = [root] queue = [root] while queue: node = queue.pop(0) if node in left_levelorder: levelorder.extend(left_levelorder[left_levelorder.index(node)+1:]) queue.extend(left_levelorder[left_levelorder.index(node)+1:]) if node in right_levelorder: levelorder.extend(right_levelorder[right_levelorder.index(node)+1:]) queue.extend(right_levelorder[right_levelorder.index(node)+1:]) return levelorder ``` 该实现使用了递归和队列,时间复杂度为 O(nlogn)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值