给定一棵二叉搜索树,请找出其中第k大的节点。
示例 1:
输入: root = [3,1,4,null,2], k = 1
3
/ \\
1 4
\\
2
输出: 4
示例 2:
输入: root = [5,3,6,2,4,null,null,1], k = 3
5
/ \\
3 6
/ \\
2 4
/
1
输出: 4
对于二叉搜索树,我们可以得知若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也分别为二叉排序树。
中序遍历
由此性质我们可以将树形结构转换为相应的数组结构,用合适的遍历方法(中序遍历)便可以按从小到大的顺序数组排列,只需找到倒数第K个元素便是所查节点。
根据中序遍历为左,根,右的顺序,我们可以得出将中序遍历倒序遍历则可得到右,根,左的顺序遍历。
var kthLargest = function (root, k) {
let res = [];
dfs(root);
return res[k-1]
function dfs(root) {
if (!root) return;
dfs(root.right);
res.push(root.val);
dfs(root.left)
}
};
二叉搜索树性质
根据二叉搜索树的性质,根节点右侧的结点都要大于根节点,而根节点左侧的结点都要小于根节点,我们假设根节点为第k大的值,那么根节点右子结点的所有子节点数cur_r一定为K-1个。所以,当k≤根节点的所有右子结点时,证明第k大的结点在根节点的右侧,而当k==根节点的所有右子结点的值cur_r+1时,这是便证明根节点为第k大的值,否则的话,第k大的值在根节点的左侧,此时的k=k-cur_r-1
var kthLargest = function (root, k) {
function getCount(root) {
if (!root) return 0;
return getCount(root.left) + getCount(root.right) + 1
}
let cur_r = getCount(root.right)
if (k <= cur_r) return kthLargest(root.right, k);
if (k == cur_r + 1) return root.val;
return kthLargest(root.left, k - cur_r - 1)
};