leetcode简单算法小结

293 阅读4分钟

  • 巧用位运算符号,例如只出现一次的数字

    func singleNumber(_ nums: [Int]) -> Int {
        //通过位运算
        var rs = 0
        for num in nums {
            rs = rs ^ num
        }
        return rs
    }

字符串

  • 巧用栈的思想去解决问题 例如棒球比赛

    func calPoints(_ ops: [String]) -> Int {
        var rs: [Int] = []
        for s in ops {
            switch s {
            case "C":
                rs.removeLast()
            case "D":
                rs.append((rs.last ?? 0) * 2)
            case "+":
                let p = rs.last ?? 0
                rs.removeLast()
                let pp = rs.last ?? 0
                rs.append(p)
                rs.append(p + pp)
            default:
                rs.append(Int(s)!)
            }
        }
        return rs.reduce(0, {$0 + $1})
    }
    当然还可以更进一步优化,在每一步进行计算得分,栈的结构只是用来完成"C""D""+"等操作,这样就可以去掉最后对数组的reduce

  • 利用ascii,例如特殊等价字符串组

    func numSpecialEquivGroups(_ A: [String]) -> Int {
        var rs: Set<String> = Set()
        for a in A {
            let t = Array(a)
            var tmp: [Int] = Array(repeating: 0, count: 52)
            for i in 0..<t.count {
                let ascii = UnicodeScalar(String(t[i]))!.value
                tmp[Int(ascii) - 97 + 26 * (i % 2)] += 1
            }
            //tmp数组转字符串
            rs.insert(tmp.reduce("", {$0 + "\($1)"}))
        }
        return rs.count
    }
    

数组

  • 动态规划的思想,例如杨辉三角

    func generate(_ numRows: Int) -> [[Int]] {
        if numRows == 0 {
            return []
        }
        if numRows == 1 {
            return [[1]]
        }
        if numRows == 2 {
            return [[1],[1,1]]
        }
        var rs: [[Int]] = [[1],[1,1]]
        for i in 3...numRows {
            var r: [Int] = []
            r.append(1)
            for j in 1..<i-1 {
                r.append(rs[i-2][j-1] + rs[i-2][j])
            }
            r.append(1)
            rs.append(r)
        }
        return rs
    }

  • 计数排序及其变种,例如数组的相对顺序

    func relativeSortArray(_ arr1: [Int], _ arr2: [Int]) -> [Int] {
        var tmp: [Int] = Array(repeating: 0, count: 1001)
        var rs: [Int] = []
        //计数
        for i in 0..<arr1.count {
            tmp[arr1[i]] += 1
        }
        //按照arr2中的顺序排序
        for i in 0..<arr2.count {
            while tmp[arr2[i]] > 0 {
                rs.append(arr2[i])
                tmp[arr2[i]] -= 1
            }
        }
        //排序不存在arr2中的,因为tmp数组的下标就是数值,所以直接遍历
        for i in 0..<1001 {
            while tmp[i] > 0 {
                rs.append(i)
                tmp[i] -= 1
            }
        }
        return rs
    }

  • 利用hash表加快查表的效率,例如拼写单词

    func countCharacters(_ words: [String], _ chars: String) -> Int {
        var searchKey: [Character: Int] = [:]
        //创建对应表
        for c in chars {
            searchKey.updateValue((searchKey[c] ?? 0) + 1, forKey: c)
        }
        var rs = 0
        for word in words {
            var tmp = searchKey
            var count = 0
            for w in word {
                if tmp.keys.contains(w) {
                    var value = tmp[w]!
                    value -= 1
                    if value == 0 {
                        tmp.removeValue(forKey: w)
                    } else {
                        tmp.updateValue(value, forKey: w)
                    }
                    count += 1
                } else {
                    count = 0
                    break
                }
            }
            rs += count
        }
        return rs
    }

链表

  • 快慢指针,可以快速找到未知长度的链表的中间节点,例如链表的中间节点,也可以通过快慢指针的方式判断链表内是否有环

    func middleNode(_ head: ListNode?) -> ListNode? {
        var fast = head
        var slow = head
        while slow?.next != nil && fast?.next != nil {
            slow = slow?.next
            fast = fast?.next?.next
        }
        return slow
    }

  • 二叉搜索树
    • 递归的方式去完成二叉搜索树的操作,例如修剪二叉搜索树

      func trimBST(_ root: TreeNode?, _ L: Int, _ R: Int) -> TreeNode? {
          guard let root = root else {
              return nil
          }
          if root.val < L {
              return trimBST(root.right, L, R)
          } else if root.val > R {
              return trimBST(root.left, L, R)
          }
          root.left = trimBST(root.left, L, R)
          root.right = trimBST(root.right, L, R)
          return root
      }

  • 深度优先
    • 先序遍历叶子相似的树

      //叶子相似的树
      func leafSimilar(_ root1: TreeNode?, _ root2: TreeNode?) -> Bool {
          var leaves1: [Int] = []
          var leaves2: [Int] = []
          _leaves(root1, &leaves1)
          _leaves(root2, &leaves2)
          return leaves1.elementsEqual(leaves2)
      }
      
      fileprivate func _leaves(_ root: TreeNode?, _ leaves: inout [Int]) {
          guard let root = root else {
              return
          }
          if root.left == nil && root.right == nil {
              leaves.append(root.val)
          }
          _leaves(root.left, &leaves)
          _leaves(root.right, &leaves)
      }

    • 中序遍历递增顺序查找树

      static var rs: TreeNode?
      func increasingBST(_ root: TreeNode?) -> TreeNode? {
          Solution.rs = TreeNode(0)
          let t = Solution.rs
          _increasingBST(root)
          return t?.right
      }
      
      fileprivate func _increasingBST(_ root: TreeNode?) {
          guard let root = root else {
              return
          }
          _increasingBST(root.left)
          let node: TreeNode = TreeNode(root.val)
          Solution.rs?.right = node
          Solution.rs = node
          _increasingBST(root.right)
      }

    • 后序遍历
  • 广度优先 例如二叉树的层平均值

    func averageOfLevels(_ root: TreeNode?) -> [Double] {
        var rs: [Double] = []
        guard let root = root else {
            return rs
        }
        //利用数组完成队列操作
        var queue: [TreeNode] = [root]
        //层序遍历 + 队列
        while !queue.isEmpty {
            //子节点数量
            let nodeCount = queue.count
            var sum = 0
            for i in 0..<nodeCount {
                let firstNode = queue.first!
                sum += firstNode.val
                queue.removeFirst()
                if let left = firstNode.left {
                    queue.append(left)
                }
                if let right = firstNode.right {
                    queue.append(right)
                }
            }
            rs.append(Double(sum)/Double(nodeCount))
        }
        return rs
    }

  • 单调递增、递减栈下一个更大元素 I

    func nextGreaterElement(_ nums1: [Int], _ nums2: [Int]) -> [Int] {
        //递减栈,使用简单数组实现
        var decreaseStack: [Int] = []
        //hash表,加快查找效率,使用简单字典实现
        var hashTable: [Int: Int] = [:]
        //遍历nums2,维护递减栈
        for i in 0..<nums2.count {
            if decreaseStack.count == 0 {
                //如果为空,则压入
                decreaseStack.append(nums2[i])
            } else {
                //遍历栈
                while decreaseStack.count > 0 && decreaseStack.last! < nums2[i] {
                    //维护字典,并将栈底弹出
                    hashTable.updateValue(nums2[i], forKey: decreaseStack.last!)
                    decreaseStack.removeLast()
                }
                decreaseStack.append(nums2[i])
            }
        }
        //遍历 num1,输出结果
        var rs: [Int] = []
        for i in 0..<nums1.count {
            rs.append(hashTable[nums1[i]] ?? -1)
        }
        return rs
    }

找规律

func minCostToMoveChips(_ chips: [Int]) -> Int {
    var odd = 0
    var even = 0
    for i in chips {
        if i % 2 == 0 {
            even += 1
        } else {
            odd += 1
        }
    }
    return min(even, odd)
}

空间几何

func projectionArea(_ grid: [[Int]]) -> Int {
    //从顶部看,面积为总共占有的格子数量
    var top = 0
    //从前面看,面积为每一行的最大数
    var front = 0
    //从侧面行,面积为每一列的最大数
    var cArray: [Int] = Array(repeating: 0, count: 50)
    for i in 0..<grid.count {
        var tmpFront = 0
        for j in 0..<grid[i].count {
            tmpFront = max(tmpFront, grid[i][j])
            if grid[i][j] != 0 {
               top += 1 
            }
            cArray[j] = max(cArray[j], grid[i][j])
        }
        front += tmpFront
    }
    let beside = cArray.reduce(0, {$0 + $1})
    return top + front + beside
}

持续更新ing...