介绍
中序遍历:左子树 -> 中 -> 右子树
二叉搜索树:中序遍历可以得到有序的序列
递归法
1.使用函数循环递归处理
2.使用一个数组来保存 k, 保证在个个递归函数中都能看到 看的变化;每访问一个节点,这个数减一,当数组中的数为1时,即访问到了第k小的数
/**
* Definition for a binary tree node.
* public class TreeNode {
* public int val;
* public TreeNode left;
* public TreeNode right;
* public TreeNode(int val=0, TreeNode left=null, TreeNode right=null) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
public class Solution {
public int KthSmallest(TreeNode root, int k) {
// 辅助结构,当 k == 1 时 表示访问到 第 k个最小的元素
int[] aux = new int[] { k };
return Traverse(root, aux);
}
// 递归访问
public int Traverse(TreeNode node, int[] aux) {
if(node == null)
{
// 用 -1 表示访问到终点
return -1;
}
// 先访问左子树
{
var val = Traverse(node.left, aux);
if(val != -1)
{
return val;
}
}
// 访问该节点
{
if(aux[0] == 1)
{
// 结果
return node.val;
}
aux[0]--;
}
// 后访问右子树
{
var val = Traverse(node.right, aux);
if(val != -1)
{
return val;
}
}
// 这里是不会走到的根据题意
return -1;
}
}
优化:
1.使用 引用传递 k, 确保递归函数都能看到k的变换
2.每次访问右子树时,不用判断直接返回结果
/**
* Definition for a binary tree node.
* public class TreeNode {
* public int val;
* public TreeNode left;
* public TreeNode right;
* public TreeNode(int val=0, TreeNode left=null, TreeNode right=null) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
public class Solution {
public int KthSmallest(TreeNode root, int k) {
// 辅助结构,当 k == 1 时 表示访问到 第 k个最小的元素
int aux = k;
return Traverse(root, ref aux);
}
// 递归访问
public int Traverse(TreeNode node, ref int aux) {
if(node == null)
{
// 用 -1 表示访问到终点
return -1;
}
// 先访问左子树
{
var val = Traverse(node.left, ref aux);
if(val != -1)
{
return val;
}
}
// 访问该节点
{
if(aux == 1)
{
// 结果
return node.val;
}
aux--;
}
// 后访问右子树
// {
// var val = Traverse(node.right, ref aux);
// if(val != -1)
// {
// return val;
// }
// }
// // 这里是不会走到的根据题意
// return -1;
// 一个优化,这里直接返回,如果没找到这里就返回-1
return Traverse(node.right, ref aux);
}
}
迭代法
1.使用数据结构Stack,模拟真实的栈处理流程
/**
* Definition for a binary tree node.
* public class TreeNode {
* public int val;
* public TreeNode left;
* public TreeNode right;
* public TreeNode(int val=0, TreeNode left=null, TreeNode right=null) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
public class Solution {
public int KthSmallest(TreeNode root, int k) {
// 借助 Stack 模拟栈
Stack<TreeNode> s = new Stack<TreeNode>();
// 先让第一个节点进栈,后面流程就处理一致了
s.Push(root);
// 根据题意一定存在结果
// while(s.Count > 0)
while(true)
{
// 访问左子树
var top = s.Peek();
if(top != null)
{
s.Push(top.left);
continue;
}
// 将null节点弹出栈
s.Pop();
// 访问当前节点,这里不用判断 s的数量,根据代码可知,这里至少存在一个节点
var visit = s.Pop();
if(k == 1)
{
// 第k最小元素
return visit.val;
}
k--;
// 访问右子树
s.Push(visit.right);
}
return -1;
}
}