1.二分木を構築する
public class TreeNode {
public var val: Int
public var left: TreeNode?
public var right: TreeNode?
public init(_ val: Int=0, _ left: TreeNode?=nil, _ right: TreeNode?=nil) {
self.val = val
self.left = left
self.right = right
}
}
复制代码
2.二分木をトラバースします
2.1。プレオーダートラバーサル(ルート-左-右)
func preorderTraversal ( _ root: TreeNode?) -> [Int] {
var r : [Int] = []
if(root?.val == nil) {
return []
} else {
r.append(root!.val)
r.append(contentsOf: preorderTraversal(root!.left))
r.append(contentsOf: preorderTraversal(root!.right))
return r
}
}
复制代码
2.2。順序のないトラバーサル(左-ルート-右)
func middenTraversal ( _ root: TreeNode?) -> [Int] {
var r : [Int] = []
if(root?.val == nil) {
return []
} else {
r.append(contentsOf: middenTraversal(root?.left))
r.append(root!.val)
r.append(contentsOf: middenTraversal(root?.right))
return r
}
}
复制代码
2.3。ポストオーダートラバーサル(左右ルート)
func postorderTraversal ( _ root: TreeNode?) -> [Int] {
var r : [Int] = []
if(root?.val == nil) {
return []
} else {
r.append(contentsOf: postorderTraversal(root?.left))
r.append(contentsOf: postorderTraversal(root?.right))
r.append(root!.val)
return r
}
}
复制代码
2.4.レイヤー順序トラバーサル(レイヤーごとのルートノードトラバーサル)
func levelOrder ( _ root: TreeNode?) -> [[Int]] {
// write code here
var res = [[Int]]()
if root == nil {
return res
}
var queue = [root!] //定义一个TreeNode队列,后续就操作这个队列
while !queue.isEmpty {
//TreeNode不为空就遍历,queue中先有一个TreeNode就是root,第2次就两个,第3次4个,依次类推,同时res中一层层地输出
let r = getNodes(queue)
res.append(r.vals)
queue = r.nodes
}
return res
}
//得到每一层的val和下一层的node
func getNodes(_ nodes:[TreeNode]) -> (vals: [Int], nodes: [TreeNode]) {
var values = [Int]()
var nextNodes = [TreeNode]()
for treeNode in nodes {
values.append(treeNode.val)
if let l = treeNode.left {
nextNodes.append(l)
}
if let r = treeNode.right {
nextNodes.append(r)
}
}
return (values, nextNodes)
}
复制代码
二叉树的遍历的顺序是相对于根结点来说的,根在前就是前序,根在中为中序,根在后为后序
3.二分木の特性の判断
3.1。二分木の最大の深さを見つける
深さは、ツリーのルートノードから任意のリーフノードまでのパス上のノードの数を指し、最大深さはすべてのリーフノードの最大深さです。
func maxDepth ( _ root: TreeNode?) -> Int {
// write code here
if(root?.val == nil) {
return 0
}
return 1 + max(maxDepth(root?.left),maxDepth(root?.right))
}
复制代码
3.2.二分木のパス合計に特定の値があるかどうか
二分木ルートと値の合計が与えられた場合、ルートノードからリーフノードまでのノード値の合計が合計に等しいかどうかを判断します
左右のサブツリーにsum-root.val値があるかどうかを単純化してから、再帰的に解決します
func hasPathSum ( _ root: TreeNode?, _ sum: Int) -> Bool {
// write code here
if root == nil {
return false
}
if root?.left == nil && root?.right == nil && sum - root!.val == 0 {
return true
}
return hasPathSum(root?.left, sum-root!.val) || hasPathSum(root?.right, sum-root!.val)
}
复制代码
3.3.二分木は対称ですか?
つまり、左右のサブツリーが対称であるかどうか
func isSymmetrical ( _ pRoot: TreeNode?) -> Bool {
// write code here
if pRoot == nil {
return true
}
return isSame(pRoot?.left, pRoot?.right)
}
func isSame(_ leftTreeNode: TreeNode?, _ rightTreeNode: TreeNode?) -> Bool {
if leftTreeNode == nil && rightTreeNode == nil {
return true
}
if leftTreeNode == nil || rightTreeNode == nil {
return false
}
return leftTreeNode?.val == rightTreeNode?.val && isSame(leftTreeNode?.left, rightTreeNode?.right) && isSame(leftTreeNode?.right, rightTreeNode?.left)
}
复制代码
3.4、二分木をマージする
2つのバイナリツリーをマージします。既存のノードがある場合は、ノード値を追加します。そうでない場合、空の位置は別のツリーのノードに置き換えられます。
func mergeTrees ( _ t1: TreeNode?, _ t2: TreeNode?) -> TreeNode? {
// write code here
if t1 == nil {
return t2
}
if t2 == nil {
return t1
}
return TreeNode(t1!.val+t2!.val, mergeTrees(t1?.left, t2?.left), mergeTrees(t1?.right, t2?.right))
}
复制代码
3.5、二分木の鏡像
指定されたバイナリツリーを操作し、ソースバイナリツリーのミラーイメージに変換します。
func Mirror ( _ pRoot: TreeNode?) -> TreeNode? {
// write code here
if pRoot == nil {
return nil
}
return TreeNode(pRoot!.val, Mirror(pRoot?.right), Mirror(pRoot?.left))
}
复制代码
4.まとめ
- 二分木の問題は、一般的に、最初に空を考慮し、次にルートノードを処理し、次に左右のサブツリーを処理します。
- 左と右のサブツリーはそれぞれ二分木であるため、二分木の問題は一般的に再帰によって処理されます
- 二分木の問題の再帰
- 再帰
- 再帰
- 再帰