LeetCode 刷题集 - 散列表、二叉树、递归(2)

散列表(上):Word 文档中的单词拼写检查功能是如何实现的?

散列表(中):如何打造一个工业级水平的散列表?

散列表(下):为什么散列表和链表经常会一起使用?

哈希算法(上):如何防止数据库中的用户信息被脱库?

哈希算法(下):哈希算法在分布式系统中有哪些应用?

二叉树基础(上):什么样的二叉树适合用数组来存储?

二叉树基础(下):有了如此高效的散列表,为什么还需要二叉树?

递归树:如何借助树来求解递归算法的时间复杂度?

树的遍历 Demo

递归代码模板

如何优雅地计算斐波那契数列

LeetCode题目:

散列表

1.有效的字母异位词

class Solution {
//     // 排序然后对比解法
// func isAnagram(_ s: String, _ t: String) -> Bool {
//         let sortedS = s.sorted()
//         let sortedT = t.sorted()
//         return sortedS == sortedT ? true : false
//     }
// hashMap
    func isAnagram(_ s: String, _ t: String) -> Bool {
        if s.count != t.count { return false }
        var dictC = Dictionary<Character, Int>()
        var dictT = Dictionary<Character, Int>()
        for c in s {
            if let count = dictC[c] {
                dictC[c] = count + 1
            } else {
                dictC.updateValue(1, forKey: c)
            }
        }
        for c in t {
            if let count = dictT[c] {
                dictT[c] = count + 1
            } else {
                dictT.updateValue(1, forKey: c)
            }
        }
        for c in s {
            if dictC[c] != dictT[c] { return false }
        }
        return true
    }
}

2.字母异位词分组

class Solution {
    func groupAnagrams(_ strs: [String]) -> [[String]] {
        var res = Array<Array<String>>()
        var dict = Dictionary<Array<Int>, String>()
        for (index, str) in strs.enumerated() {
            let a: String = "a"
            let aNum = a.unicodeScalars.first!.value
            var key = Array(repeating: 0, count: 26)
            for c in str {
                key[Int(c.unicodeScalars.first!.value - aNum)] += 1
            }
            if dict[key] != nil {
                dict[key]! += "\(index),"
            } else {
                dict[key] = "\(index),"
            }
        }
        for (_, var value) in dict {
            value.removeLast()
            let indexArray = value.components(separatedBy: ",")
            var finalArray = Array<String>()
            for i in indexArray {
                finalArray.append(strs[Int(i)!])
            }
            res.append(finalArray)
        }
        return res
    }
}

二叉树

3.二叉树的前序遍历

class Solution {
        func preorderTraversal(_ root: TreeNode?) -> [Int] {
        var res = Array<Int>()
        preOrder(root, res: &res)
        return res
    }
    func preOrder(_ root: TreeNode?, res: inout Array<Int>) {
        // terminator
        if root == nil { return }
        // process current logic
        res.append(root!.val)
        // drill down
        preOrder(root?.left, res: &res)
        preOrder(root?.right, res: &res)
    }
}

4.N 叉树的前序遍历

class Solution {
        func preorder(_ root: Node?) -> [Int] {
            var res = Array<Int>()
            preorder(root, res: &res)
            return res
        }
        func preorder(_ root: Node?, res: inout Array<Int>) {
            if root == nil { return }
            res.append((root!.val))
            for i in 0..<(root?.children.count)! {
                preorder(root?.children[i], res: &res)
            }
        }
}

5.二叉树的中序遍历

class Solution {
     func inorderTraversal(_ root: TreeNode?) -> [Int] {
        var res = Array<Int>()
        inorder(root, res: &res)
        return res
    }
    func inorder(_ root: TreeNode?, res: inout Array<Int>) {
        if root == nil { return }
        inorder(root?.left, res: &res)
        res.append(root!.val)
        inorder(root?.right, res: &res)
    }
}

6.N 叉树的后序遍历

class Solution {
    func postorder(_ root: Node?) -> [Int] {
        var res = Array<Int>()
        postOrder(root, res: &res)
        return res
    }
    func postOrder(_ root: Node?, res: inout Array<Int>) {
        // terminator
        if root == nil { return }
        // process current logic
        for i in 0..<(root?.children.count)! {
            // drill down
            postOrder(root?.children[i], res: &res)
        }
        res.append(root!.val)
    }
}

7.N 叉树的层序遍历

class Solution {
    // 递归解法
    // func levelOrder(_ root: Node?) -> [[Int]] {
    //     var res = Array<Array<Int>>()
    //     var level = 0
    //     processOrder(root, res: &res, level: level)
    //     return res
    // }
    // func processOrder(_ root: Node?, res: inout Array<Array<Int>>, level: Int) {
    //     if root == nil { return }
    //     if res.count <= level {
    //         res.append([])
    //     }
    //     res[level].append(root!.val)
    //     let newLevel = level + 1
    //     for i in 0..<(root?.children.count)! {
    //         processOrder(root?.children[i], res: &res, level: newLevel)
    //     }
    // }
    //BFS解法
   func levelOrder(_ root: Node?) -> [[Int]] {
       guard let root = root else { return []}
       var queue = Array<Node?>()
       var res = Array<Array<Int>>()
        queue = [root]
       while !queue.isEmpty {
           let levelCount = queue.count
           var temp = Array<Int>()
           for _ in 0..<levelCount {
            let node = queue.removeFirst()
            temp.append(node!.val)
            node!.children.forEach { queue.append($0) }
           }
           res.append(temp)
       }
       return res
    }
}

8.翻转二叉树

class Solution {
    func invertTree(_ root: TreeNode?) -> TreeNode? {
        if root == nil { return nil}
        let left = invertTree(root?.left)
        let right = invertTree(root?.right)
        root?.left = right
        root?.right = left
        return root
    }
}

9.验证二叉搜索树

class Solution {
        func isValidBST(_ root: TreeNode?) -> Bool {
        var res = true
        var lower = Int64.min
        backTrack(root: root, lower: &lower, res: &res)
        return res
    }
    func backTrack(root: TreeNode?, lower: inout Int64, res: inout Bool) {
        // 左根右
        if root == nil {
            return }
        backTrack(root: root?.left, lower: &lower, res: &res)
        if lower >= root!.val {
            res = false
        }
        lower = Int64(root!.val)
        backTrack(root: root?.right, lower: &lower, res: &res)
    }

}

10.二叉树的最大深度

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

11.二叉树的最小深度

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

12.二叉树的序列化与反序列化

class Codec {
    func serialize(_ root: TreeNode?) -> String {
        guard let nonNilRoot = root else {
            return ""
        }
        return BFS(root: nonNilRoot)
    }
    func deserialize(_ data: String) -> TreeNode? {
        if data == "" {return nil}
        let NodeValueArray = data.split(separator: ",")
        // 构造一个TreeNode数组
        var treeNodeArray = Array<TreeNode?>()
        for i in NodeValueArray {
            if i == "Null" {
                treeNodeArray.append(nil)
            } else {
                treeNodeArray.append(TreeNode(Int(i)!))
            }
        }
        let resRoot:TreeNode? = treeNodeArray.first!
        var queue = Array<TreeNode?>()
        queue = [resRoot]
        var i = 1
        while !queue.isEmpty {
            if let currentRoot = queue.removeFirst() {
                if let left = treeNodeArray[i] {
                    currentRoot.left = left
                    queue.append(left)
                }
                if let right = treeNodeArray[i + 1] {
                    currentRoot.right = right
                    queue.append(right)
                }
                i += 2
            }
        }
        return resRoot
    }
    func BFS(root: TreeNode?) -> String {
        guard let root = root else {
            return ""
        }
        var queue: [TreeNode?] = [root]
        var res = "\(root.val),"
        while !queue.isEmpty {
            for _ in 0..<queue.count {
                let currentNode = queue.removeFirst()
                if let left = currentNode?.left {
                    queue.append(left)
                    res += "\(left.val),"
                } else {
                    res += "Null,"
                }
                if let right = currentNode?.right {
                    queue.append(right)
                    res += "\(right.val),"
                } else {
                    res += "Null,"
                }
                
            }
        }
        res.removeLast()
        return res
    }
}
// Your Codec object will be instantiated and called as such:
// var ser = Codec()
// var deser = Codec()
// deser.deserialize(ser.serialize(root))

13.二叉树的最近公共祖先

class Solution {
    func lowestCommonAncestor(_ root: TreeNode?, _ p: TreeNode?, _ q: TreeNode?) -> TreeNode?{
        if root == nil || root?.val == p?.val || root?.val == q?.val {
             return root
        }
        let left = lowestCommonAncestor(root?.left, p, q)
        let right = lowestCommonAncestor(root?.right, p, q)
        if left == nil  { return right }
        if right == nil { return left }
        return root
    }
}

14.从前序与中序遍历序列构造二叉树

class Solution {
func buildTree(_ preorder: [Int], _ inorder: [Int]) -> TreeNode? {
        var mPreorder = preorder
        var mInorder = inorder
        return backTrack(preorderNodeArray: &mPreorder, inorderNodeArray: &mInorder)
    }
    func backTrack(preorderNodeArray: inout [Int], inorderNodeArray: inout [Int]) -> TreeNode? {
        guard let rootVal = preorderNodeArray.first else {
            return nil
        }
        let root = TreeNode(rootVal)
        if preorderNodeArray.count == 1 {
            return root
        }
        var inorderLeftTree = Array(inorderNodeArray[0..<inorderNodeArray.firstIndex(of: root.val)!])
        var inorderRighTree = Array(inorderNodeArray[inorderNodeArray.firstIndex(of: root.val)! + 1..<inorderNodeArray.count])
        var preorderLeftTree = Array(preorderNodeArray[1..<inorderLeftTree.count + 1])
        var preorderRightTree = Array(preorderNodeArray[(inorderLeftTree.count + 1)..<preorderNodeArray.count])
        root.left = backTrack(preorderNodeArray: &preorderLeftTree, inorderNodeArray: &inorderLeftTree)
        root.right = backTrack(preorderNodeArray: &preorderRightTree, inorderNodeArray: &inorderRighTree)
        return root
    }
}

递归

9.括号生成

class Solution {
func generateParenthesis(_ n: Int) -> [String] {
        var res = Array<String>()
        backTrack(n: n, left: 0, right: 0, res: &res, cur: "")
        return res
    }
    func backTrack(n: Int, left: Int, right: Int, res: inout Array<String>, cur: String) {
        // terminator
        if cur.count == n * 2 {
            // process result
            res.append(cur)
            return
        }
        if left < n {
            backTrack(n: n, left: left + 1, right: right, res: &res, cur: cur + "(")
        }
        if right < left {
            backTrack(n: n, left: left, right: right + 1, res: &res, cur: cur + ")")
        }
    }
}

15.组合

class Solution {
    func combine(_ n: Int, _ k: Int) -> [[Int]] {
        var res = Array<Array<Int>>()
        var cur = Array<Int>()
        backTracking(n: n, k: k, res: &res, cur: &cur, curNum: 1)
        return res
    }
    func backTracking(n: Int, k: Int, res: inout Array<Array<Int>>, cur: inout Array<Int>, curNum: Int) {
        if cur.count + (n - curNum + 1) < k {
            return
        }
        if cur.count == k {
            res.append(cur)
            return
        }
        cur.append(curNum)
        backTracking(n: n, k: k, res: &res, cur: &cur, curNum: curNum + 1)
        cur.removeLast()
        backTracking(n: n, k: k, res: &res, cur: &cur, curNum: curNum + 1)
    }

}

16.全排列

class Solution {
func permute(_ nums: [Int]) -> [[Int]] {
        var path = Array<Int>()
        var res = Array<Array<Int>>()
        var used = Array(repeating: false, count: nums.count)
        dfs(path: &path, res: &res, used: &used, nums: nums, depth: 0)
        return res
    }
    func dfs(path: inout Array<Int>, res: inout Array<Array<Int>>, used: inout Array<Bool>, nums: Array<Int>, depth: Int) {
        if depth == nums.count {
            res.append(path)
            return
        }
        for i in 0..<nums.count {
            if used[i] { continue }
            path.append(nums[i])
            used[i] = true
            dfs(path: &path, res: &res, used: &used, nums: nums, depth: depth + 1)
            path.removeLast()
            used[i] = false
        }
    }
}

17.全排列 II

class Solution {
    func permuteUnique(_ nums: [Int]) -> [[Int]] {
        var res = Array<Array<Int>>()
        var path = Array<Int>()
        var used = Array(repeating: false, count: nums.count)
        dfs(nums: nums.sorted(by: <), res: &res, path: &path, level: 0, used: &used)
        return res
    }
    func dfs(nums: [Int], res: inout [[Int]], path: inout [Int], level: Int, used: inout [Bool]) {
        if level == nums.count {
            res.append(path)
            return
        }
        for i in 0..<nums.count {
            // !used[i - 1] 保证在填【i】这个数的时候重复数字只会被填入一次,只要最左边的。所以如果两个数字相同,并且前一个还没有用过,那么是不符合规则(用最左侧)的。要continue跳过
            if used[i] == true || (i > 0 && nums[i] == nums[i - 1] && !used[i - 1]) {
                continue
            }
            used[i] = true
            path.append(nums[i])
            dfs(nums: nums, res: &res, path: &path, level: level + 1, used: &used)
            path.removeLast()
            used[i] = false
        }
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,793评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,567评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,342评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,825评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,814评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,680评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,033评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,687评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,175评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,668评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,775评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,419评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,020评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,206评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,092评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,510评论 2 343

推荐阅读更多精彩内容