劍指offer計劃20( 搜尋與回溯演算法中等)---java

叫我阿康就行 發表於 2021-09-20
Java 演算法

1.1、題目1

劍指 Offer 07. 重建二叉樹

1.2、解法

註釋解法。

1.3、程式碼


class Solution {
    int[] preorder;
    HashMap<Integer, Integer> map = new HashMap<>();
    // 前序遍歷 preorder: 根 -- 左 -- 右   第一個肯定是根節點
    // 中序遍歷 inorder: 左 -- 根 -- 右
    public TreeNode buildTree(int[] preorder, int[] inorder) {
        this.preorder = preorder;
        for(int i = 0; i < inorder.length; i++){
            map.put(inorder[i], i);
        }
        return rebuild(0, 0, inorder.length - 1);  
    }

    // pre_root_index : 根節點 在 前序遍歷中的下標
    // in_left_index: 該節點在中序遍歷中的左邊界
    // in_right_index: 該節點在中序遍歷中的右邊界
    public TreeNode rebuild(int pre_root_index, int in_left_index, int in_right_index){
       if(in_left_index > in_right_index)  return null;
       // 根節點在中序遍歷中的位置:in_root_index
       int in_root_index = map.get(preorder[pre_root_index]);
       // 建立一個根節點
       TreeNode node = new TreeNode(preorder[pre_root_index]);
       // 尋找node的左節點: 
       // 在前序遍歷中的位置就是  根節點的下標 + 1(右邊一個單位)
       // 在中序遍歷中的位置就是: 1. 左邊界不變,2. 右邊界就是根節點的左邊一個單位 in_root_index - 1
       node.left = rebuild(pre_root_index + 1, in_left_index, in_root_index - 1);
       // 尋找node的右節點: 
       // 在前序遍歷中的位置就是  根節點的下標 + 左子樹長度 + 1
       // 在中序遍歷中的位置就是: 1. 左邊界在根節點的右邊一個單位  in_root_index + 1, 2. 右邊界不變
       node.right = rebuild(pre_root_index + in_root_index - in_left_index + 1, in_root_index + 1, in_right_index);
       return node;
    }
}



2.1、題目2

劍指 Offer 16. 數值的整數次方

2.2、解法

分類討論,判斷內容,通過將數拆開兩半來減少效能消耗(容易棧溢位)

2.3、程式碼


class Solution {
    public double myPow(double x, int n) {
        if(n<0) return 1/(x*myPow(x,-n-1)) ;
        else if(n==0) return 1;
        else if(n==1) return x;
        else{
            double res=myPow(x,n/2);
            return res*res*myPow(x,n%2);
        
        }
    }
}




3.1、題目3

劍指 Offer 33. 二叉搜尋樹的後序遍歷序列

3.2、解法

遞迴開始判斷,找到第一個大於根節點的值,然後找出左子樹和右子樹的兩個區間,
通過遞迴再次判斷

3.3、程式碼

class Solution {
    public boolean verifyPostorder(int[] postorder) {
        return recur(postorder,0,postorder.length - 1);
    }
    boolean recur(int[] postorder, int start, int end){
        if(start >= end) return true;
        int temp = start; 
        // 找到右子樹結點第一次出現的地方。(或者說是遍歷完整棵左子樹)
        for(int i = start; i <= end; ++i){
            if(postorder[i] < postorder[end]){
                temp = i;
            }
            else break;
        }
        int rightTreeNode = temp + 1; // 後序遍歷右子樹時會訪問的第一個結點的下標。
        // 驗證右子樹所有結點是否都大於根結點。
        for(int i = rightTreeNode; i <= end; ++i){
            if(postorder[i] > postorder[end])
                ++rightTreeNode;
        }
        return rightTreeNode == end && recur(postorder,start,temp) && recur(postorder,temp + 1,end - 1);
    }
}