繁体   English   中英

SINGLE递归函数,用于打印/获取二进制搜索树中的第k个最小元素

[英]SINGLE Recursive function for Print/Fetch kth smallest element in Binary search tree

我正在尝试在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

这可以使用一个单独的count函数实现,该函数看起来像

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;
    }


}

这是打印正确的答案,但是要多次打印,我弄清楚了为什么要打印多次,却不了解如何避免打印。 而且,如果我想返回节点而不只是打印,该怎么办? 谁能帮我这个忙吗?

目的:

在二进制搜索树中递归地找到第k个最小的元素,并返回与该元素对应的节点。

观察:

小于当前元素的元素数量是左子树的大小,因此,我们不是在递归地计算其大小,而是在class Node引入了一个新成员,即lsize ,它表示当前节点左子树的大小。

解:

在每个节点上,我们将左子树的大小与k的当前值进行比较:

  1. 如果head.lsize + 1 == k :我们的答案中的当前节点。
  2. 如果head.lsize + 1 > k :左子树中的元素大于k,即最小的元素k位于左子树中。 所以,我们走了。
  3. 如果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);
    }

变化:

  1. class Node引入了新的成员lsize
  2. insertIntoBstinsertIntoBst修改。
  3. printKthElement主要更改。

角壳:

添加检查以确保k1和树的大小之间,否则将返回null节点,从而导致NullPointerException

到目前为止,这正在处理我尝试过的测试用例。 任何建议或更正是最欢迎的。 :)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM