1. 程式人生 > >九章演算法筆記 3.二叉樹與分治演算法Binary Tree & Divide Conquer

九章演算法筆記 3.二叉樹與分治演算法Binary Tree & Divide Conquer

大綱 cs3k.com

• 時間複雜度訓練 II

• 二叉樹的遍歷演算法 Traverse in Binary Tree

Preorder / Inorder / Postorder

• 二叉樹的深度優先搜尋 DFS in Binary Tree

1.遍歷問題 Preorder / Inorder / Postorder
2.分治演算法 Introduce Divide Conquer Algorithm
3.非遞迴 遍歷法 分治法 Non-recursion vs Traverse vs Divide Conquer
4.二叉搜尋樹 Binary Search Tree : Insert / Remove / Find / Validate

時間複雜度訓練 II

cs3k.com

通過O(n)的時間,把n的問題,變為了兩個n/2的問題,複雜度是多少?

T(n) = 2Tn/2) + O(n)

= 2 * 2T(n/4) + O(n) + O(n)

=n + nlogn

FullSizeRender-12-03-17-23-26-5通過O(1)的時間,把n的問題,變成了兩個n/2的問題,複雜度是多少?

T(n) = 2T(n/2) + O(1)

= 2 * 2T(n/4) + O(1) + O(1)

=n + (1 + 2 + 4 +…+ n)

≈n + 2n

≈O(n)

二叉樹的時間複雜度呢?

也是T(n) = 2T(n/2) + O(1)

即使是不平衡的二叉樹, T(n) = T(x) + T(n-x-1) + O(1), 最後也是拆成n個O(1)相加

比如:

FullSizeRender-12-03-17-23-26-4

所以, 二叉樹基本都是O(n)的複雜度**

二叉樹的遍歷演算法 Traverse in Binary Tree

Screenshot from 2017-03-12 20-11-35

前序遍歷

cs3k.com

 

Screenshot from 2017-03-12 20-15-27

 

中序遍歷

Screenshot from 2017-03-12 20-20-32

後序遍歷

Screenshot from 2017-03-12 20-21-08

Divide Conquer Algorithm

cs3k.com

Traverse vs Divide Conquer

1.遞迴是實現方式,遍歷和分治是可以用遞迴實現的演算法思想

2.Result in parameter vs Result in return value

3.Top down vs Bottom up

4.Traverse的結果要改引數,返回引數. Divide conquer的結果直接return,是個更好的介面,因為給你什麼引數最好不要改.

Screenshot from 2017-03-12 20-36-28

非遞迴做遍歷和遞迴做遍歷的區別?

非遞迴其實是模擬遞迴用的stack

為什麼自己模擬的可以, 呼叫計算機的就不行呢?

因為我們new出來的stack在heap memory裡面, 能用的空間≈ memory size

stack memory ≈ process memory是計算機分給每個程式的一個很小的獨佔的空間,所以遞迴的深度太深,就不夠用了

前序遍歷

TRAVERSE

是一個小人, 拿著一個記事本, 順著二叉樹走, 走過一個, 在本子上面記下來

FullSizeRender-12-03-17-23-26-3

Screenshot from 2017-03-12 20-15-40

DIVIDE & CONQUER

是女王接到這個任務, 找兩個小弟A和B, 讓A和B先去收集, A收集了[2, 4, 5], B收集了[3], 最後女王把A, B的結果彙總加上自己是1,得到答案[1, 2, 4, 5, 3]

FullSizeRender-12-03-17-23-26-2

Screenshot from 2017-03-12 21-24-24.png

遞迴三要素

1.遞迴的定義:接什麼參,返什麼值->求以root為根的preorder並返回

2.遞迴的拆解

3.出口

理解的順序是123, 寫程式的順序是132

遞迴的出口是選NULL還是葉子節點?

1.有一個corner case是直接就傳一個null的節點進來, 所以要選null

2.葉子節點比較複雜, 只要判斷null的return之後結果ok, 就null

Maximum Depth of Binary Tree

cs3k.com

Given a binary tree, find its maximum depth.

The maximum depth is the number of nodes along the longest path from the root node down to the farthest leaf node.

Screenshot from 2017-03-12 21-37-19.png

這道題divide conquer比較簡單, 因為traverse要遊走,邊走還得邊在記事本上記錄最大深度, 需要全域性變數.

Binary Tree Paths

Given a binary tree, return all root-to-leaf paths.

Screenshot from 2017-03-12 21-41-38.png

寫完出口先無腦派下去

再把結果加上去

最後檢查一遍corner case, 再單獨處理下子節點有null的情況

Minimum Subtree

cs3k.com

Given a binary tree, find the subtree with minimum sum. Return the root of the subtree.

LintCode will print the subtree which root is your return node.

It’s guaranteed that there is only one subtree with minimum sum and the given binary tree is not an empty tree.

如果能for一下多好, 就可以用大擂臺來算了, 所以我們用打擂臺加分治

Screenshot from 2017-03-12 22-01-55.png

 

也可以使用divide conquer

Balanced Binary Tree

Given a binary tree, determine if it is height-balanced.

For this problem, a height-balanced binary tree is defined as a binary tree in which the depth of the two subtrees of every node never differ by more than 1.

這道題根節點和兒子節點的關係理解:

cs3k.com

1.左子樹是平衡的

2.右子數是平衡的

3.左右高度差≤1

divide and conquer要return兩個值, 要建個class或者 struct, c++可以用pair

用全域性變數的是traverse演算法

Screenshot from 2017-03-12 22-08-34Screenshot from 2017-03-12 22-08-52

Subtree with Maximum Average

Given a binary tree, find the subtree with maximum average. Return the root of the subtree.

LintCode will print the subtree which root is your return node.

It’s guaranteed that there is only one subtree with maximum average.

最好把sum和size都記下來

sumA/sizeA   >  sumB/sizeB比較可以化作

sumA * sizeB   >  sumB * sizeA

如果用除法的話, size為0無意義, 而且精度有流失

用乘法的話, 容易溢位, 所以最好用long

Screenshot from 2017-03-12 22-16-43Screenshot from 2017-03-12 22-15-55

 Flattern Binary Tree to Linked List

Flatten a binary tree to a fake “linked list” in pre-order traversal.

Here we use the right pointer in TreeNode as the next pointer in ListNode.

Don’t forget to mark the left child of each node to null. Or you will get Time Limit Exceeded or Memory Limit Exceeded.

 

思路:

先把左右子樹flattern了, 再把root的右接左子樹, 左子樹的最後接右子樹 FullSizeRender-12-03-17-23-26-1
Screenshot from 2017-03-12 22-24-21  

Screenshot from 2017-03-12 22-24-36

Screenshot from 2017-03-12 22-24-49

Lowest Common Ancestor

Given the root and two nodes in a Binary Tree. Find the lowest common ancestor(LCA) of the two nodes.

The lowest common ancestor is the node with largest depth which is the ancestor of both nodes.

Assume two nodes are exist in tree.

cs3k.com

Screenshot from 2017-03-12 22-26-55.png

LCA II

Given the root and two nodes in a Binary Tree. Find the lowest common ancestor(LCA) of the two nodes.

The lowest common ancestor is the node with largest depth which is the ancestor of both nodes.

The node has an extra attribute parent which point to the father of itself. The root’s parent is null.

Screenshot from 2017-03-12 22-29-40

5出發 5 7 4

6出發 6 7 4

最近的是7

自己也可以是自己的祖先, 倒著for迴圈一下

LCA III

cs3k.com

Given the root and two nodes in a Binary Tree. Find the lowest common ancestor(LCA) of the two nodes.
The lowest common ancestor is the node with largest depth which is the ancestor of both nodes.
Return null if LCA does not exist.

node A or node B may not exist in tree.

需要搞個result type

Screenshot from 2017-03-12 22-37-31Screenshot from 2017-03-12 22-37-50

Binary Tree Longest Consecutive Sequence

cs3k.com

Given a binary tree, find the length of the longest consecutive sequence path.

The path refers to any sequence of nodes from some starting node to any node in the tree along the parent-child connections. The longest consecutive path need to be from parent to child (cannot be the reverse).

兩個問題: 1.從root走, 最長序列多少? 並且和root能不能接上 2.找到全域性的最優序列 Screenshot from 2017-03-12 22-41-04.png

Binary Tree Path Sum

Given a binary tree, find all paths that sum of the nodes in the path equals to a given number target.

A valid path is from root node to any of the leaf nodes.

traverse

邊走變加

divide conquer

Screenshot from 2017-03-12 22-43-56

從1出來找和為5的path, 所以我們就要在2和4的位置上找和為(5-1)=4的path

Screenshot from 2017-03-12 22-47-06.png

稍後其它答案?

Binary Tree Path Sum II

cs3k.com

Your are given a binary tree in which each node contains a value. Design an algorithm to get all paths which sum to a given value. The path does not need to start or end at the root or a leaf, but it must go in a straight line down.

不要求在根出發,不要求在葉子節點結束,只要不拐彎就行

Screenshot from 2017-03-12 23-03-17.png

分為三個問題:

1.path在左

2.path在右

3.path以root開始

難的是一定以1開始, 和為6, 又是一個分治, 分為:

一定以2出發和一定以3出發的

Screenshot from 2017-03-12 23-07-52.png

Binary Tree Path Sum III

Give a binary tree, and a target number, find all path that the sum of nodes equal to target, the path could be start and end at any node in the tree.

可以拐彎, 最多可以拐幾個彎?

一個!

以最多拐一個彎為突破點:

不拐的理解為在第一個點拐彎

所以以每個點為拐點的路徑,就traverse了所有

FullSizeRender-12-03-17-23-26

其中x是什麼?  for一下

Screenshot from 2017-03-12 23-07-22.png

Binary Search Tree

Given a binary tree, determine if it is a valid binary search tree (BST).

Assume a BST is defined as follows:

  • The left subtree of a node contains only nodes with keys less than the node’s key.
  • The right subtree of a node contains only nodes with keys greater than the node’s key.
  • Both the left and right subtrees must also be binary search trees.
  • A single node tree is a BST

驗證二叉查詢樹:

1.traverse  挨個和上一個比比打小

Screenshot from 2017-03-12 23-16-02

2.divide conquer和左最大以及右最小比較

Screenshot from 2017-03-12 23-15-55  

quick sort

cs3k.com

public class Solution {
    /**
     * @param A an integer array
     * @return void
     */
    public void sortIntegers2(int[] A) { quickSort(A, 0, A.length - 1); } private void quickSort(int[] A, int start, int end) { if (start >= end) { return; } int left = start, right = end; // key point 1: pivot is the value, not the index int pivot = A[(start + end) / 2]; // key point 2: every time you compare left & right, it should be // left <= right not left < right while (left <= right) { // key point 3: A[left] < pivot not A[left] <= pivot while (left <= right && A[left] < pivot) { left++; } // key point 3: A[right] > pivot not A[right] >= pivot while (left <= right && A[right] > pivot) { right--; } if (left <= right) { int temp = A[left]; A[left] = A[right]; A[right] = temp; left++; right--; } } quickSort(A, start, right); quickSort(A, left, end); } } 

錯誤一:

        while (left < right) { // key point 3: A[left] < pivot not A[left] <= pivot while (left < right && A[left]