swift刷算法笔记(三) - 栈 二叉树 综合使用

69 阅读10分钟

一个值是可选的拿来使用要强制解包 或者判空 .的时候可选的 一定要加?

232.用栈实现队列

代码随想录

leecode

  • 你只能使用标准的栈操作 -- 也就是只有 push to top, peek/pop from top, size, 和 is empty 操作是合法的。

  • void push(int x) 将元素 x 推到队列的末尾

  • int pop() 从队列的开头移除并返回元素

  • int peek() 返回队列开头的元素

  • boolean empty() 如果队列为空,返回 true ;否则,返回 false

栈只能用popLast() 函数

image.png

image.png



class MyQueue {
   var stackIn  = [Int]()
   var stackOut = [Int]()

    init() {
    }
    
    func push(_ x: Int) {
       stackIn.append(x)
    }
    
    // 
    func pop() -> Int {
       if stackOut.isEmpty {
          while !stackIn.isEmpty {
             stackOut.append(stackIn.popLast()!)
          }
       }
       return   stackOut.popLast() ?? -1
    }
    
    // 返回队列开头的元素 
    func peek() -> Int {
       // 移除队列的最开始元素 
      var res = pop()
      // 最开始元素移除了需要加到出栈的栈顶 
      stackOut.append(res)
      return res
    }

    
    func empty() -> Bool {
       return stackIn.isEmpty && stackOut.isEmpty
    }
}

/**
 * Your MyQueue object will be instantiated and called as such:
 * let obj = MyQueue()
 * obj.push(x)
 * let ret
 _2: Int = obj.pop()
 * let ret_3: Int = obj.peek()
 * let ret_4: Bool = obj.empty()
 */

225. 用队列实现栈

简单

请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作

leecode

队列实现栈

image.png

代码实现

// 用单个数组模拟队列 
class Qunue {
    var arr = [Int]()
    init() {
    }
   
    func push(_ x: Int) {
       arr.append(x)
    }
    
    func pop() -> Int {
      return arr.removeFirst() ?? -1 
    }
    
    func top() -> Int {
     
       return arr.first ?? -1
    }
    
    func empty() -> Bool {
       return arr.count == 0 
    } 

    func count() -> Int {
        return arr.count
    }
}

//2个队列模拟栈 
class MyStack {
    var qunueMain = Qunue()
    var qunueTemp = Qunue()
    init() {
      
    }
    
    func push(_ x: Int) {
        qunueMain.push(x)
    }
    
    // 栈是先进后出 
    // 此处队列是先进先去 
    // 通过pop方法 拿到first 
    func pop() -> Int {
       if qunueMain.empty()  {
           return -1
       }
       // 主队列不为空 
       while qunueMain.count() > 1 {
           let res = qunueMain.pop()
           // 主动列的后面拿出来,加入临时中 
           qunueTemp.push(res)
       }
       var res = qunueMain.pop()
       while !qunueTemp.empty() {
         qunueMain.push(qunueTemp.pop())
       }
       return res

    }
    
    func top() -> Int {
       // 栈的顶部元素 
       var res = pop()
       // 放到主队列的末尾 .   难点 
       qunueMain.push(res)
       return res 
    }
    
    func empty() -> Bool {
       return qunueMain.empty()  && qunueTemp.empty()
    }
}

/**
 * Your MyStack object will be instantiated and called as such:
 * let obj = MyStack()
 * obj.push(x)
 * let ret_2: Int = obj.pop()
 * let ret_3: Int = obj.top()
 * let ret_4: Bool = obj.empty()
 */

20. 有效的括号

给定一个只包括 '('')''{''}''['']' 的字符串 s ,判断字符串是否有效。

有效字符串需满足:

  1. 左括号必须用相同类型的右括号闭合。
  2. 左括号必须以正确的顺序闭合。
  3. 每个右括号都有一个对应的相同类型的左括号。

 

示例 1:

输入: s = "()"
输出: true

示例 2:

输入: s = "()[]{}"
输出: true

示例 3:

输入: s = "(]"
输出: false
class Solution {
    func isValid(_ s: String) -> Bool {
       var arr = Array(s)
       var res = [Character]()
       for i in arr {
           if i == "(" {
               res.append(")")
           } else if i == "[" {
               res.append("]")
           } else if i == "{" {
               res.append("}")
           } else {
          
               if res.last == i {
                    res.removeLast()
               } else {
                   return false
               }
           }
       }
       return res.isEmpty 
    }
}

1047. 删除字符串中的所有相邻重复项

leetcode.cn/problems/re… 给出由小写字母组成的字符串 S重复项删除操作会选择两个相邻且相同的字母,并删除它们。

在 S 上反复执行重复项删除操作,直到无法继续删除。

在完成所有重复项删除操作后返回最终的字符串。答案保证唯一。

  示例:

输入: "abbaca"
输出: "ca"
解释:
例如,在 "abbaca" 中,我们可以删除 "bb" 由于两字母相邻且相同,这是此时唯一可以执行删除操作的重复项。之后我们得到字符串 "aaca",其中又只有 "aa" 可以执行重复项删除操作,所以最后的字符串为 "ca"
class Solution {
    func removeDuplicates(_ s: String) -> String {
        var array = Array(s)
        var res = [Character]()
        for i in array {
            let last = res.last
            if i == last {
                res.removeLast()
            } else {
                res.append(i)
            }
        }
        return String(res)
    }
}

150. 逆波兰表达式求值

给你一个字符串数组 tokens ,表示一个根据 逆波兰表示法 表示的算术表达式。

请你计算该表达式。返回一个表示表达式值的整数。

注意:

  • 有效的算符为 '+''-''*' 和 '/' 。
  • 每个操作数(运算对象)都可以是一个整数或者另一个表达式。
  • 两个整数之间的除法总是 向零截断 。
  • 表达式中不含除零运算。
  • 输入是一个根据逆波兰表示法表示的算术表达式。
  • 答案及所有中间计算结果可以用 32 位 整数表示。

 

示例 1:

输入: tokens = ["2","1","+","3","*"]
输出: 9
解释: 该算式转化为常见的中缀算术表达式为:((2 + 1) * 3) = 9

示例 2:

输入: tokens = ["4","13","5","/","+"]
输出: 6
解释: 该算式转化为常见的中缀算术表达式为:(4 + (13 / 5)) = 6

    class Solution {
        func evalRPN(_ tokens: [String]) -> Int {
            var stack = [Int]()
            for i in tokens {
                if isNumber(i) {
                    stack.append(Int(i)!)
                } else {
                    let left = stack.removeLast()
                    let right = stack.removeLast() // 注意点 左右顺序 
                    print("left right, \(left),\(right)")
                    // 注意点: switch 语句 
                    switch i {
                        case "+":
                            let res = left + right
                            stack.append(res)
                        case "-":
                            let res = right - left
                            stack.append(res)

                        case "*":
                           let res = left * right
                            stack.append(res)

                        case "/":
                        // 错误 case语句 
                            let res = right / left
                            stack.append(res)
                        default:
                          break
                    }
                }
            }
            return stack.last!

        }
        // 错误 Bool
        func isNumber(_ ch:String) -> Bool {
           // 注意点  : 是不是数字 
           return Int(ch) != nil 
        }
    }

347. 前 K 个高频元素

给你一个整数数组 nums 和一个整数 k ,请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案。

 

示例 1:

输入: nums = [1,1,1,2,2,3], k = 2
输出: [1,2]

示例 2:

输入: nums = [1], k = 1
输出: [1]

 

提示:

  • 1 <= nums.length <= 105
  • k 的取值范围是 [1, 数组中不相同的元素的个数]
  • 题目数据保证答案唯一,换句话说,数组中前 k 个高频元素的集合是唯一的

 

进阶: 你所设计算法的时间复杂度 必须 优于 O(n log n) ,其中 n **是数组大小。

class Solution {
    func topKFrequent(_ nums: [Int], _ k: Int) -> [Int] {
        // 出现的次数保存起来 
        var dic:Dictionary<Int,Int> = [:]
        var arr:Array<Int> = []
        for i in nums {
            dic[i] = dic[i, default:0] + 1
        }

        // 对次数排序  ,注意点 字典的排序 
        var dicNew = dic.sorted{(d1,d2) -> Bool in  
            return d1.value > d2.value
        }
        // 拿到数据 
        for i in 0..<k {
           arr.append(dicNew[i].key)
        }
        return arr
    }
}

二叉树

看如下中间节点的顺序,就可以发现,中间节点的顺序就是所谓的遍历方式

  • 前序遍历:中左右
  • 中序遍历:左中右
  • 后序遍历:左右中

二叉树的前序遍历

        /**
         * Definition for a binary tree node.
         * public class TreeNode {
         *     public var val: Int
         *     public var left: TreeNode?
         *     public var right: TreeNode?
         *     public init() { self.val = 0; self.left = nil; self.right = nil; }
         *     public init(_ val: Int) { self.val = val; self.left = nil; self.right = nil; }
         *     public init(_ val: Int, _ left: TreeNode?, _ right: TreeNode?) {
         *         self.val = val
         *         self.left = left
         *         self.right = right
         *     }
         * }
         */
        class Solution {
            var arr: Array<Int> = []
            func preorderTraversal(_ root: TreeNode?) -> [Int] {
                if root == nil {
                    return []
                } 
                traver(root)
                return arr
            }

            func traver(_ root:TreeNode?) {
                if root == nil {
                    return
                }
                arr.append(root!.val)
                traver(root!.left)
                traver(root!.right)
            }

        }

迭代

class Solution {
    var arr: Array<Int> = []
    var st: Array<TreeNode> = []
    func preorderTraversal(_ root: TreeNode?) -> [Int] {
        if root == nil {
            return []
        } 
        st.append(root!)
        while !st.isEmpty  {
            let node = st.removeLast()
            if node != nil {
               arr.append(node.val)
            }
             if node.right != nil {
                st.append(node.right!)
             }
              if node.left != nil {
                st.append(node.left!)
             }
        }
        return arr
    }
}

后续遍历

       class Solution {
          var arr: Array<Int> = []
          func postorderTraversal(_ root: TreeNode?) -> [Int] {
              traver(root)
              return arr
          }
          func traver(_ root: TreeNode?) {
              if root == nil {
                  return 
              }
              traver(root!.left)
              traver(root!.right)
              arr.append(root!.val)
          }
       }

class Solution {
    var arr: Array<Int> = []
    var st: Array<TreeNode> = []
    func preorderTraversal(_ root: TreeNode?) -> [Int] {
        if root == nil {
            return []
        } 
        st.append(root!)
        while !st.isEmpty  {
            let node = st.removeLast()
            if node != nil {
               arr.append(node.val)
            }
             if node.right != nil {
                st.append(node.right!)
             }
              if node.left != nil {
                st.append(node.left!)
             }
        }
        return arr
    }
}

102. 二叉树的层序遍历

给你二叉树的根节点 root ,返回其节点值的 层序遍历 。 (即逐层地,从左到右访问所有节点)。

 

示例 1:

输入: root = [3,9,20,null,null,15,7]
输出: [[3],[9,20],[15,7]]

示例 2:

输入: root = [1]
输出: [[1]]

示例 3:

输入: root = []
输出: []
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     public var val: Int
 *     public var left: TreeNode?
 *     public var right: TreeNode?
 *     public init() { self.val = 0; self.left = nil; self.right = nil; }
 *     public init(_ val: Int) { self.val = val; self.left = nil; self.right = nil; }
 *     public init(_ val: Int, _ left: TreeNode?, _ right: TreeNode?) {
 *         self.val = val
 *         self.left = left
 *         self.right = right
 *     }
 * }
 */
class Solution {
    var result = [[Int]]()
    func levelOrder(_ root: TreeNode?) -> [[Int]] {
        guard root != nil else {
            return []
        }
        var result = [[Int]]()
        var qunue = [TreeNode]()
        var nextQuene = [TreeNode]()
        qunue.append(root!)
        while qunue.count > 0 {
            var temp = [Int]()
            for node in qunue {
              temp.append(node.val)
              if node.left != nil {
                nextQuene.append(node.left!)
              }

              if node.right != nil {
                 nextQuene.append(node.right!)
              }
            }
            result.append(temp)
            qunue.removeAll()
            qunue = nextQuene
            nextQuene.removeAll()
        }
        return result 
    }
}

226. 翻转二叉树

给你一棵二叉树的根节点 root ,翻转这棵二叉树,并返回其根节点。

 

示例 1:

输入: root = [4,2,7,1,3,6,9]
输出: [4,7,2,9,6,3,1]

示例 2:

输入: root = [2,1,3]
输出: [2,3,1]

示例 3:

输入: root = []
输出: []

 

提示:

  • 树中节点数目范围在 [0, 100] 内
  • -100 <= Node.val <= 100

递归进行反转

// 前序遍历-递归
func invertTree(_ root: TreeNode?) -> TreeNode? {
 guard let root = root else {
     return root
 }
 let tmp = root.left
 root.left = root.right
 root.right = tmp
 let _ = invertTree(root.left)
 let _ = invertTree(root.right)
 return root
}

迭代法进行反转

class Solution {
    func invertTree(_ root: TreeNode?) -> TreeNode? {
        if root == nil {
            return nil
        }
        var qunue: Array<TreeNode> = []
        qunue.append(root!)
        while !qunue.isEmpty {
            // 取出交换 
             let node : TreeNode = qunue.removeFirst()
             (node.right, node.left) = (node.left, node.right)
              if let node = node.left {  qunue.append(node)  }
              if let node = node.right { qunue.append(node)   }
        }
        return root!
    }
}

101. 对称二叉树

简单

给你一个二叉树的根节点 root , 检查它是否轴对称。

 

示例 1:

输入: root = [1,2,2,3,4,4,3]
输出: true

示例 2:

输入: root = [1,2,2,null,3,null,3]
输出: false

 

提示:

  • 树中节点数目在范围 [1, 1000] 内
  • -100 <= Node.val <= 100

 

进阶: 你可以运用递归和迭代两种方法解决这个问题吗?

class Solution {
    func isSymmetric(_ root: TreeNode?) -> Bool {
      
        return compare(root!.left,root!.right)
    }
    
    func compare(_ leftRoot: TreeNode? , _ rightRoot: TreeNode? ) -> Bool {
         if leftRoot == nil && rightRoot != nil {
             return false 
         } else if leftRoot != nil && rightRoot == nil {
             return false 
         }else if leftRoot == nil && rightRoot == nil {
             return true 
         }else if(leftRoot!.val != rightRoot!.val) {
             return false 
         }
        
        // 数值相等 那么继续递归
        let  left =   compare(leftRoot!.left,rightRoot!.right )
        let  right =   compare(leftRoot!.right,rightRoot!.left)
        return left&&right   
    }

}

    class Solution {
        func isSymmetric(_ root: TreeNode?) -> Bool {
            if root == nil {
                return true 
            }
            var qunue:[TreeNode?] = []
            // 注意点 
            qunue.append(root!.left)
            qunue.append(root!.right)

            while !qunue.isEmpty {
                var left: TreeNode? = qunue.removeFirst()
                var right: TreeNode? = qunue.removeFirst()
              
                // 注意点 
                if left == nil && right == nil {
                    continue
                }
                if  left == nil  || right == nil  || left?.val != right?.val {
                    return false
                }
                // 注意点 
                qunue.append(left!.left)
                qunue.append(right!.right)
                qunue.append(left!.right)
                qunue.append(right!.left)

            }
            return true 
        }
    }

104. 二叉树的最大深度

相关企业

给定一个二叉树,找出其最大深度。

二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。

说明: 叶子节点是指没有子节点的节点。

示例:
给定二叉树 [3,9,20,null,null,15,7]

    3
   / \
  9  20
    /  \
   15   7

返回它的最大深度 3 。

class Solution {
    func maxDepth(_ root: TreeNode?) -> Int {
        if root == nil {
            return 0 
        }
        return 1 + max(maxDepth(root!.left),maxDepth(root!.right))
    }
}

111.二叉树的最小深度

力扣题目链接(opens new window)

给定一个二叉树,找出其最小深度。

最小深度是从根节点到最近叶子节点的最短路径上的节点数量。

说明: 叶子节点是指没有子节点的节点。

示例:

给定二叉树 [3,9,20,null,null,15,7],

111.二叉树的最小深度1

返回它的最小深度 2.

lianjie

《代码随想录》算法视频公开课:看起来好像做过,一写就错! | LeetCode:111.二叉树的最小深度 (opens new window),相信结合视频在看本篇题解,更有助于大家对本题的理解。

看完了这篇104.二叉树的最大深度 (opens new window),再来看看如何求最小深度。

直觉上好像和求最大深度差不多,其实还是差不少的。

本题依然是前序遍历和后序遍历都可以,前序求的是深度,后序求的是高度。

  • 二叉树节点的深度:指从根节点到该节点的最长简单路径边的条数或者节点数(取决于深度从0开始还是从1开始)
  • 二叉树节点的高度:指从该节点到叶子节点的最长简单路径边的条数后者节点数(取决于高度从0开始还是从1开始)

那么使用后序遍历,其实求的是根节点到叶子节点的最小距离,就是求高度的过程,不过这个最小距离 也同样是最小深度。

以下讲解中遍历顺序上依然采用后序遍历(因为要比较递归返回之后的结果,本文我也给出前序遍历的写法)。

本题还有一个误区,在处理节点的过程中,最大深度很容易理解,最小深度就不那么好理解,如图:

111.二叉树的最小深度

这就重新审题了,题目中说的是:最小深度是从根节点到最近叶子节点的最短路径上的节点数量。 ,注意是叶子节点

什么是叶子节点,左右孩子都为空的节点才是叶子节点!

原文链接


    class Solution {
        func minDepth(_ root: TreeNode?) -> Int {
            guard let root = root else {
                return 0
            }

             var leftH = 0 
             var rightH = 0
             if root.left == nil && root.right != nil {
                 return  1 + minDepth(root.right)
             }

             if root.right == nil && root.left != nil {
                return  1 + minDepth(root.left)
             }
             return 1 +  min(minDepth(root.left),minDepth(root.right))

        }
    }

迭代的解法

class Solution {
    func minDepth(_ root: TreeNode?) -> Int {
        guard let root = root else {
            return 0 
        }
        var qunue: Array<TreeNode> = []
        qunue.append(root)
        var res = 0 
        while !qunue.isEmpty {
            res += 1
            for _ in 0..<qunue.count {
                var node: TreeNode = qunue.removeFirst()
                if node.left == nil && node.right == nil {
                    return res 
                }

                if node.left != nil {
                    qunue.append(node.left!)
                }
                 if node.right != nil {
                    qunue.append(node.right!)
                }
            }
        }
        return res 
    }
}

222.完全二叉树的节点个数

力扣题目链接(opens new window)

给出一个完全二叉树,求出该树的节点个数。

示例 1:

  • 输入:root = [1,2,3,4,5,6]
  • 输出:6

示例 2:

  • 输入:root = []
  • 输出:0

示例 3:

  • 输入:root = [1]
  • 输出:1

提示:

  • 树中节点的数目范围是[0, 5 * 10^4]
  • 0 <= Node.val <= 5 * 10^4
  • 题目数据保证输入的树是 完全二叉树

链接

《代码随想录》算法视频公开课:要理解普通二叉树和完全二叉树的区别! | LeetCode:222.完全二叉树节点的数量 (opens new window),相信结合视频在看本篇题解,更有助于大家对本题的理解。

本篇给出按照普通二叉树的求法以及利用完全二叉树性质的求法。

普通二叉树

首先按照普通二叉树的逻辑来求。

这道题目的递归法和求二叉树的深度写法类似, 而迭代法,二叉树:层序遍历登场! (opens new window)遍历模板稍稍修改一下,记录遍历的节点数量就可以了。

递归遍历的顺序依然是后序(左右中)。

递归

如果对求二叉树深度还不熟悉的话,看这篇:二叉树:看看这些树的最大深度 (opens new window)

  1. 确定递归函数的参数和返回值:参数就是传入树的根节点,返回就返回以该节点为根节点二叉树的节点数量,所以返回值为int类型。

代码如下:

int getNodesNum(TreeNode* cur) {

1

  1. 确定终止条件:如果为空节点的话,就返回0,表示节点数为0。

代码如下:

if (cur == NULL) return 0;

1

  1. 确定单层递归的逻辑:先求它的左子树的节点数量,再求右子树的节点数量,最后取总和再加一 (加1是因为算上当前中间节点)就是目前节点为根节点的节点数量。

代码如下:

    int leftNum = getNodesNum(cur->left);      // 左
    int rightNum = getNodesNum(cur->right);    // 右
    int treeNum = leftNum + rightNum + 1;      // 中
    return treeNum;
class Solution {
    func countNodes(_ root: TreeNode?) -> Int {
        guard let  root = root else {
            return 0
        }  
        let leftCount = countNodes(root.left)
        let rightCount = countNodes(root.right)
        return 1 + leftCount + rightCount

    }
}

迭代法

class Solution {
    func countNodes(_ root: TreeNode?) -> Int {
        guard let  root = root else {
            return 0
        }  
        var qunue = [root]
        var res = 0 
        while !qunue.isEmpty {
            for _ in 0..<qunue.count {
                var  node = qunue.removeFirst()
                res += 1 
                if let node = node.left {
                    qunue.append(node)
                }

                 if let node = node.right {
                    qunue.append(node)
                }
            }
        }
        return res 
    }
}

110.平衡二叉树

力扣题目链接(opens new window)

给定一个二叉树,判断它是否是高度平衡的二叉树。

本题中,一棵高度平衡二叉树定义为:一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过1。

示例 1:

给定二叉树 [3,9,20,null,null,15,7]

110.平衡二叉树

返回 true 。

示例 2:

给定二叉树 [1,2,2,3,3,null,null,4,4]

110.平衡二叉树1

返回 false 。

《代码随想录》算法视频公开课:后序遍历求高度,高度判断是否平衡 | LeetCode:110.平衡二叉树 (opens new window),相信结合视频在看本篇题解,更有助于大家对本题的理解

链接

咋眼一看这道题目和104.二叉树的最大深度 (opens new window)很像,其实有很大区别。

这里强调一波概念:

  • 二叉树节点的深度:指从根节点到该节点的最长简单路径边的条数。
  • 二叉树节点的高度:指从该节点到叶子节点的最长简单路径边的条数。

但leetcode中强调的深度和高度很明显是按照节点来计算的,如图:

110.平衡二叉树2

关于根节点的深度究竟是1 还是 0,不同的地方有不一样的标准,leetcode的题目中都是以节点为一度,即根节点深度是1。但维基百科上定义用边为一度,即根节点的深度是0,我们暂时以leetcode为准(毕竟要在这上面刷题)。

因为求深度可以从上到下去查 所以需要前序遍历(中左右),而高度只能从下到上去查,所以只能后序遍历(左右中)

    class Solution {
        func countNodes(_ root: TreeNode?) -> Int {
            guard let  root = root else {
                return 0
            }  
            var qunue = [root]
            var res = 0 
            while !qunue.isEmpty {
                for _ in 0..<qunue.count {
                    var  node = qunue.removeFirst()
                    res += 1 
                    if let node = node.left {
                        qunue.append(node)
                    }

                     if let node = node.right {
                        qunue.append(node)
                    }
                }
            }
            return res 
        }
    }

257. 二叉树的所有路径

力扣题目链接(opens new window)

给定一个二叉树,返回所有从根节点到叶子节点的路径。

说明: 叶子节点是指没有子节点的节点。

示例: 257.二叉树的所有路径1

链接

《代码随想录》算法视频公开课:递归中带着回溯,你感受到了没?| LeetCode:257. 二叉树的所有路径 (opens new window),相信结合视频在看本篇题解,更有助于大家对本题的理解

这道题目要求从根节点到叶子的路径,所以需要前序遍历,这样才方便让父节点指向孩子节点,找到对应的路径。

在这道题目中将第一次涉及到回溯,因为我们要把路径记录下来,需要回溯来回退一个路径再进入另一个路径。

前序遍历以及回溯的过程如图:

257.二叉树的所有路径

我们先使用递归的方式,来做前序遍历。要知道递归和回溯就是一家的,本题也需要回溯。 原文链接

    class Solution {
        var res  = [String]()

        func binaryTreePaths(_ root: TreeNode?) -> [String] {
           guard let root = root else {
               return []
           }
           var path = ""
            path2(root, path)
            return res

        }
        
        func path2(_ root:TreeNode? , _ path:  String )  {
            var path = path 
            guard let root = root else {
                return 
            }
            // 找到路劲 
            
            if root.left == nil && root.right == nil {
                // 最终节点加到数组中
                path += String(root.val)
                res.append(path)
                return 
            }
            var pathNew = path + String(root.val) + "->" 

            path2(root.left, pathNew)
            path2(root.right, pathNew)

        }
    }