我正在尝试在BST中打印第k个最小元素。 第一种解决方案是使用有序遍历。 下一个解决方案是通过计算其左子树的大小来查找当前节点的索引。 完整的算法:
Find size of left subtree:
1.If size = k-1, return current node
2.If size>k return (size-k)th node in right subtree
3.If size<k return kth node in left subtree
这可以使用单独的计数功能实现,类似于
public class Solution {
public int kthSmallest(TreeNode root, int k) {
//what happens if root == null
//what happens if k > total size of tree
return kthSmallestNode(root,k).val;
}
public static TreeNode kthSmallestNode(TreeNode root,int k){
if(root==null) return root;
int numberOfNodes = countNodes(root.left);
if(k == numberOfNodes ) return root;
if(k<numberOfNodes ) return kthSmallestNode(root.left,k);
else return kthSmallestNode(root.right,k-numberOfNodes );
}
private static int countNodes(TreeNode node){
if(node == null) return 0;
else return 1+countNodes(node.left)+countNodes(node.right);
}
}
但是我看到我们多次计算相同树的大小,所以一种方法是维护一个数组来存储像DP一样的大小。
但我想为此编写一个递归解决方案。这里是我编写的代码。
class Node {
int data;
Node left;
Node right;
public Node(int data, Node left, Node right) {
this.left = left;
this.data = data;
this.right = right;
}
}
public class KthInBST
{
public static Node createBST(int headData)
{
Node head = new Node(headData, null, null);
//System.out.println(head.data);
return head;
}
public static void insertIntoBst(Node head, int data)
{
Node newNode = new Node(data, null, null);
while(true) {
if (data > head.data) {
if (head.right == null) {
head.right = newNode;
break;
} else {
head = head.right;
}
} else {
if (head.left == null) {
head.left = newNode;
break;
} else {
head = head.left;
}
}
}
}
public static void main(String[] args)
{
Node head = createBST(5);
insertIntoBst(head, 7);
insertIntoBst(head, 6);
insertIntoBst(head, 2);
insertIntoBst(head, 1);
insertIntoBst(head, 21);
insertIntoBst(head, 11);
insertIntoBst(head, 14);
insertIntoBst(head, 3);
printKthElement(head, 3);
}
public static int printKthElement(Node head, int k)
{
if (head == null) {
return 0;
}
int leftIndex = printKthElement(head.left, k);
int index = leftIndex + 1;
if (index == k) {
System.out.println(head.data);
} else if (k > index) {
k = k - index;
printKthElement(head.right, k);
} else {
printKthElement(head.left, k);
}
return index;
}
}
这是打印正确的答案,但多次,我弄清楚为什么它多次打印但不了解如何避免它。 并且如果我想返回节点而不是仅仅打印我该怎么做? 有人可以帮我这个吗?
答案 0 :(得分:0)
递归地在二叉搜索树中找到第k个最小元素,并返回与该元素对应的节点。
小于当前元素的元素数量是左子树的大小,所以我们不是递归地计算它的大小,而是在class Node
中引入一个新成员,即lsize
代表当前节点左子树的大小。
在每个节点,我们将左子树的大小与k
的当前值进行比较:
head.lsize + 1 == k
:我们答案中的当前节点。head.lsize + 1 > k
:左子树中的元素大于k,也就是说,最小元素的k位于左子树中。所以,我们走了。head.lsize + 1 < k
:当前元素连同左子树中的所有元素都小于我们需要找到的第k个元素。因此,我们转到右子树,但也减少k左子树+ 1(当前元素)中的元素数量。通过从k
中减去它,我们确保已经考虑了小于k
并且作为当前节点的左子树(包括当前节点本身)的元素的数量。 class Node {
int data;
Node left;
Node right;
int lsize;
public Node(int data, Node left, Node right) {
this.left = left;
this.data = data;
this.right = right;
lsize = 0;
}
}
public static void insertIntoBst(Node head, int data) {
Node newNode = new Node(data, null, null);
while (true) {
if (data > head.data) {
if (head.right == null) {
head.right = newNode;
break;
} else {
head = head.right;
}
} else {
head.lsize++; //as we go left, size of left subtree rooted
//at current node will increase, hence the increment.
if (head.left == null) {
head.left = newNode;
break;
} else {
head = head.left;
}
}
}
}
public static Node printKthElement(Node head, int k) {
if (head == null) {
return null;
}
if (head.lsize + 1 == k) return head;
else if (head.lsize + 1 > k) return printKthElement(head.left, k);
return printKthElement(head.right, k - head.lsize - 1);
}
lsize
。class Node
insertIntoBst
。printKthElement
。添加检查以确保k
介于1
和树的大小之间,否则将返回null
节点,从而生成NullPointerException
。
到目前为止,这是我试过的测试用例。任何建议或更正都是最受欢迎的。 :)