基礎算法題-樹相關

1. 輸入某二叉樹的前序遍歷和中序遍歷的結果,請重建出該二叉樹。

可用遞歸方式解決。首先利用前序遍歷集合的根節點,將中序遍歷和前序遍歷的結果各分割成兩部分,爲左右子樹的前序遍歷集合和中序遍歷集合。
代碼如下:

TreeNode reConstructBinaryTree(int[] pre, int[] in) {
    if (in.length == 0 | pre.length == 0) return null;
    TreeNode treeNode = new TreeNode(pre[0]);
    int count = 0;
    for (int i = 0; i < in.length; i++) {
        if (in[i] == pre[0]) break;
        count++;
    }
    int[] pre2 = new int[count];
    int[] in2 = new int[count];
    int[] pre3 = new int[in.length - count - 1];
    int[] in3 = new int[in.length - count - 1];
    for (int j = 0; j < count; j++) {
        pre2[j] = pre[1 + j];
        in2[j] = in[j];
    }
    for (int k = 0; k < in.length - count - 1; k++) {
        pre3[k] = pre[count + 1 + k];
        in3[k] = in[count + 1 + k];
    }
    treeNode.left = reConstructBinaryTree(pre2, in2);
    treeNode.right = reConstructBinaryTree(pre3, in3);
    return treeNode;
}
2. 輸入兩棵二叉樹A,B,判斷B是不是A的子結構。

遞歸實現。分別判斷B是A的子結構,B是否是A左右子樹的子結構即可。
代碼如下:

boolean HasSubtree(TreeNode root1, TreeNode root2) {
    if (root2 == null | root1 == null) return false;
    return IsSimilarity(root1, root2) | HasSubtree(root1.right, root2) | HasSubtree(root1.left, root2);
}

boolean IsSimilarity(TreeNode root1, TreeNode root2) {
    if (root2 == null) return true;
    if (root1 == null) return false;
    if (root1.val == root2.val) {
        return IsSimilarity(root1.left, root2.left) && IsSimilarity(root1.right, root2.right);
    } else {
        return false;
    }
}
3. 操作給定的二叉樹,將其變換爲源二叉樹的鏡像。

遞歸實現。先鏡像根節點的左右子樹,再將左右子樹互換。兩者操作順序不影響結果。
代碼如下:

void Mirror(TreeNode root) {
    if (root == null) return;
    Mirror(root.left);
    Mirror(root.right);

    TreeNode node = root.left;
    root.left = root.right;
    root.right = node;
}
4. 從上往下打印出二叉樹的每個節點,同層節點從左至右打印。

利用隊列即可。代碼如下:

ArrayList<Integer> PrintFromTopToBottom(TreeNode root) {
    if (root == null) return null;
    ArrayList<Integer> array = new ArrayList<Integer>();
    LinkedList<TreeNode> queue = new LinkedList<TreeNode>();
    queue.add(root);
    while (!queue.isEmpty()) {
        TreeNode pointer = queue.poll();
        array.add(pointer.val);
        if (pointer.left != null)
            queue.add(pointer.left);
        if (pointer.right != null)
            queue.add(pointer.right);
    }
    return array;
}
5. 輸入一個整數數組,判斷該數組是不是某二叉搜索樹的後序遍歷的結果。

遞歸解決。先找數組尾部的頭結點,通過頭結點找出數組左右子樹的分割點。分割點右邊的數應該都比頭結點值大。再將左右子樹遞歸判斷即可。
代碼如下:

boolean VerifySquenceOfBST(int[] sequence) {
    if (sequence.length < 1) return false;
    int index = sequence.length - 1;
    return VerifySquence(sequence, 0, index);
}

boolean VerifySquence(int[] array, int begin, int last) {
    int length = last - begin + 1;
    if (length < 3) return true;
    if (length > 2) {
        int root = array[last];
        int mid = 0;
        boolean flag = false;
        for (int i = begin; i <= last; i++) {
            if (array[i] > root) {
                mid = i - 1;
                flag = true;
            }
            if (flag && array[i] < root) {
                return false;
            }
        }
        return VerifySquence(array, begin, mid) && VerifySquence(array, mid + 1, last - 1);
    }
    return false;
}
6. 輸入一顆二叉樹和一個整數,打印出二叉樹中結點值的和爲輸入整數的所有路徑。路徑定義爲從樹的根結點開始往下一直到葉結點所經過的結點形成一條路徑。

通過一個List記錄路徑,當遇到葉子結點時,路徑值和剛好等於目標值。則將這條路保存,然後移除List中的葉子路徑,再探測其他路徑。若大於目標值,則直接返回即可。可遞歸實現。
代碼如下:

ArrayList<ArrayList<Integer>> path = new ArrayList<ArrayList<Integer>>();
ArrayList<Integer> array = new ArrayList<Integer>();

ArrayList<ArrayList<Integer>> FindPath(TreeNode root, int target) {
    if (root == null) return path;
    if (root.val > target) return path;
    if (root.left == null && root.right == null && target == root.val) {
        array.add(root.val);
        path.add((ArrayList<Integer>) array.clone());
        array.remove((Integer) root.val);
    }
    if (root != null) {
        array.add(root.val);
        FindPath(root.left, target - root.val);
        FindPath(root.right, target - root.val);
        array.remove((Integer) root.val);
    }
    return path;
}
7. 輸入一棵二叉搜索樹,將該二叉搜索樹轉換成一個排序的雙向鏈表。要求不能創建任何新的結點,只能調整樹中結點指針的指向。

首先將左右子樹遞歸改成雙向鏈表,然後配置左右子樹與根節點的關係。將根節點放置在左子樹的最右邊結點的後面。將右子樹的最左邊的結點的left指向根節點。然後一道雙向鏈表的最左端結點,返回即可。
代碼如下:

TreeNode Convert(TreeNode pRootOfTree) {
    if (pRootOfTree == null) return null;
    if (pRootOfTree != null) {
        TreeNode node = Convert(pRootOfTree.left);
        while (node != null && node.right != null) {
            node = node.right;
        }
        if (node != null) {//要注意邊界 爲null的情況
            node.right = pRootOfTree;
        }
        pRootOfTree.left = node;
        TreeNode node1 = Convert(pRootOfTree.right);
        pRootOfTree.right = node1;
        if (node1 != null) {
            node1.left = pRootOfTree;
        }
    }
    while (pRootOfTree.left != null) {
        pRootOfTree = pRootOfTree.left;
    }
    return pRootOfTree;
}
8. 輸入一棵二叉樹,判斷該二叉樹是否是平衡二叉樹。

首先通過獲取樹的深度,然後判斷左右子樹深度之差是否符合平衡。遞歸解決。
代碼如下:

boolean IsBalanced_Solution(TreeNode root) {
    if (root == null) return true;
    boolean left = IsBalanced_Solution(root.left);
    boolean right = IsBalanced_Solution(root.right);
    if (left && right) {
        int depthLeft = TreeDepth(root.left);
        int depthRight = TreeDepth(root.right);
        if (Math.abs(depthLeft - depthRight) < 2)
            return true;
        else
            return false;
    }
    return left && right;
}

int TreeDepth(TreeNode root) {
    if (root == null) return 0;
    int depthLeft = TreeDepth(root.left);
    int depthRight = TreeDepth(root.right);
    return depthLeft > depthRight ? depthLeft + 1 : depthRight + 1;
}
9. 請實現一個函數,用來判斷一顆二叉樹是不是對稱的。注意,如果一個二叉樹同此二叉樹的鏡像是同樣的,定義其爲對稱的。

遞歸實現,分別判斷左右子樹的左右子樹是否對應相等。
代碼如下:

boolean isSymmetrical(TreeNode pRoot) {
    if (pRoot == null) 
         return true;
    return isSymm(pRoot.left, pRoot.right);
}

boolean isSymm(TreeNode pRoot1, TreeNode pRoot2) {
    if (pRoot1 == null && pRoot2 == null)
        return true;
    if (pRoot1 != null && pRoot2 != null) {
        if (pRoot1.val == pRoot2.val)
            return isSymm(pRoot1.left, pRoot2.right) & isSymm(pRoot1.right, pRoot2.left);
    }
    return false;
}
10. 請實現兩個函數,分別用來序列化和反序列化二叉樹。

在每個結點的值後添加’,’,null結點用’#’表示,利用中序遍歷的方式序列化。利用index記錄復原到哪一位字符。
代碼如下:

int index = -1;

String Serialize(TreeNode root) {
    if (root == null) return "#,";
    StringBuilder str = new StringBuilder();
    str.append(root.val + ",");
    str.append(Serialize(root.left));
    str.append(Serialize(root.right));
    return str.toString();
}

TreeNode Deserialize(String str) {
    index++;
    if (index >= str.length())
        return null;
    String[] parts = str.split(",");
    TreeNode root = null;
    if (!parts[index].equals("#")) {
        root = new TreeNode(Integer.parseInt(parts[index]));
        root.left = Deserialize(str);
        root.right = Deserialize(str);
    }
    return root;
}
11. 給定一顆二叉搜索樹,請找出其中的第k大的結點。

先統計左子樹的數量,若大於K則k結點肯定在左子樹中,若小於K則第k個結點可能在根節點或者右子樹中。可遞歸調用。
代碼如下:

TreeNode KthNode(TreeNode pRoot, int k) {
    if (pRoot == null) return null;
    int count;
    TreeNode result = pRoot;
    count = getNumOfNodes(pRoot.left);
    if (count >= k)
        return KthNode(pRoot.left, k);
    else if (count + 1 < k)
        return KthNode(pRoot.right, k - count - 1);
    else
        return pRoot;
}

int getNumOfNodes(TreeNode pRoot) {
    if (pRoot == null) return 0;
    int count = 1;
    count = count + getNumOfNodes(pRoot.left) + getNumOfNodes(pRoot.right);
    return count;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章