劍指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;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章