剑指offer 62_二叉搜索树的第k个结点(java)

二叉搜索树的第k个结点

思路

采用中序遍历,天然的就是升序,则找到中序遍历的第k个节点就行~~~

写法1 – 递归

/*
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;

    }

}
*/
// 考虑二叉搜索数的性质,中序遍历的结果就是升序的,那么遍历到第k个节点就行。
public class Solution {
    int n = 0;
    TreeNode res = null;
    TreeNode KthNode(TreeNode pRoot, int k)
    {
        mid(pRoot, k);
        return res;
        
    }
    void mid(TreeNode node, int k){
        if(k < 0 || node == null) return;
        // 先判断考虑左子树
        mid(node.left,k);
        n++;
        // 判断自己;
        if(n == k) {
            res = new TreeNode(node.val);
            return ;
        }
        // 判断右子树。
        mid(node.right, k);
    }
}

写法二 – 迭代

把递归改写成迭代的写法;用栈来存储遍历的节点。

import java.util.Stack;
// 考虑二叉搜索数的性质,中序遍历的结果就是升序的,那么遍历到第k个节点就行。
public class Solution {
    TreeNode KthNode(TreeNode pRoot, int k)
    {
        if (pRoot == null || k < 0) return null;
        TreeNode cur = pRoot;
        TreeNode res = null;
        int n = 0;
        Stack<TreeNode> stack = new Stack<>();
        while(cur != null || !stack.empty()){
            while(cur != null){
                stack.push(cur);
                cur = cur.left;  // 循环结束,cur指向null
            }
            cur = stack.pop(); // 找完左子树,找右子树,要先定位最左子树。
            n++;// k是从第一开始算的....
            if(n == k){
                res = new TreeNode(cur.val);
                break;
            }
            cur = cur.right;
        }
        return res;
    }
}

二叉树的Morris遍历算法

morris讲解

Morris一种中序遍历法,能以O(1)的空间复杂度O(n)的时间复杂度实现二叉树的中序遍历。

核心是找某个节点的前序节点。

算法步骤:
1, 根据当前节点,找到其前序节点,如果前序节点的右孩子是空,那么把前序节点的右孩子指向当前节点,然后进入当前节点的左孩子。
2. 如果当前节点cur的左孩子为空,打印当前节点,然后进入cur的右孩子。
3. 如果当前节点的前序节点其右孩子指向了它本身,那么把前序节点的右孩子设置为空,打印当前节点,然后进入右孩子。

// 考虑二叉搜索数的性质,中序遍历的结果就是升序的,那么遍历到第k个节点就行。
public class Solution {
    TreeNode KthNode(TreeNode pRoot, int k)
    {
        int n = 0;
        if(pRoot == null || k < 1) return null;
        TreeNode res = null;
        TreeNode cur = pRoot;
        while(cur != null){  // 如果当前节点不为空,去找它的前节点。其前序应该是它的左孩子的最右节点。
            if(cur.left == null){  // 如果它的左子树为空,证明cur是中序中首先被访问的节点,下一个节点会出去访问它的右孩子。
                n++;  // 记录cur被访问了;
                if(n == k){ 
                    res = new TreeNode(cur.val);
                    break;
                }
                cur = cur.right;
            }else{  // 如果有左子树,则要去找左子树的最右孩子。
                TreeNode pre = cur.left;  // 记录cur的前序节点。
                // 找左子树的最右节点,该节点就是cur的前序节点!!!
                // 另外,morris需要在第一次找前序节点的是由,如果该前序节点的右孩子为空,需要让右孩子指向cur;
                while(pre.right != null && pre.right != cur){
                    pre = pre.right;
                }
                if(pre.right == null){
                    pre.right = cur; // 让左孩子的最右孩子指向cur;
                    cur = cur.left;
                }
                if(pre.right == cur){
                    n++;
                    if(n == k){
                        res = new TreeNode(cur.val);
                        break;
                    }
                    pre.right = null;
                    cur = cur.right; 
                }
            }
        }
        return res;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章