iOS 面试题(四)- 常见算法题

426 阅读2分钟

常见算法题(也有自己 leetCode 刷的一些题,不断更新)

链表和数组的区别是什么?插入和查询的时间复杂度分别是多少?

  • 链表和数组都是一个有序的集合,数组需要连续的内存空间,而链表不需要
  • 链表的插入删除的时间复杂度是O(1),数组是O(n)
  • 根据下标查询的时间复杂度数组是O(1),链表是O(n)
  • 根据值查询的时间复杂度,链表和数组都是O(n)

哈希表是如何实现的?如何解决地址冲突?

  • 哈希表是也是通过数组来实现的,首先对key值进行哈希化得到一个整数,然后对整数进行计算,得到一个数组中的下标,然后进行存取
  • 解决地址冲突常用方法有开放定址法和链表法
  • runtime源码的存放weak指针哈希表使用的就是开放定址法,Java里的HashMap使用的是链表法

如何检测链表中是否有环?

//  快慢指针法
class ListNode {
    var next :ListNode?
    var val :Int = 0
    init(_ val:Int) {
        self.val = val
        self.next = nil
    }
    
}
extension ListNode{
    func haveCycle()->Bool{
        
        var fast = self.next
        var slow:ListNode? = self
        while fast != nil {
            if fast === slow{
                return true
            }
            slow = slow?.next
            fast = fast?.next?.next
        }
        return false
    }
}
//调用
let node = ListNode(2)
let node1 = ListNode(3)
let node2 = ListNode(4)
let node3 = ListNode(5)
node.next = node1
node1.next = node2
node2.next = node3
node3.next = node2

print(node.haveCycle())

删除链表的节点

//剑指 Offer 18. 删除链表的节点
func deleteNode(_ head: ListNode?, _ val: Int) -> ListNode? {
    if head?.val == val{
       return head?.next;
    }
    let node:ListNode? = ListNode(0)
    node?.next = head
    var currentNode:ListNode? = node?.next
    var preNode:ListNode? = node
      while currentNode != nil{
         if currentNode?.val == val{
            preNode?.next = currentNode?.next
         }
          preNode = currentNode
         
         currentNode = currentNode?.next
      }
    return node?.next
}

反转链表

//剑指 Offer 24. 反转链表 递归的基本用法
func reverseList(_ head: ListNode?) -> ListNode? {
  return reList(nil, head)
}
func reList(_ pre:ListNode?,_ cur:ListNode?)->ListNode?{
    guard let _cur = cur else {
        return pre
    }
    let res = reList(_cur, _cur.next)
    _cur.next = pre
    return res
}

从尾到头打印链表

//剑指 Offer 06. 从尾到头打印链表
func reversePrint(_ head: ListNode?) -> [Int] {
    
    guard  head != nil else {
        return [Int]()
    }
    
    var arr = [Int]()
    var ahead = head
    while ahead != nil {
        arr.append(ahead!.val)
        ahead = ahead?.next
        
    }
    return arr.reversed()
}

反转二叉树

public class TreeNode {
     public var val: Int
     public var left: TreeNode?
     public var right: TreeNode?
     public init(_ val: Int) {
         self.val = val
         self.left = nil
         self.right = nil
     }
 }
//反转二叉树
@discardableResult
func invertTree(_ root: TreeNode?) -> TreeNode? {
    guard let root = root else{
        return nil
    }
    let temp = root.left
    root.left = root.right
    root.right = temp
    
    invertTree(root.left)
    invertTree(root.right)
    return root
    
}

验证两个二叉树是完全相等的嘛

//验证两个二叉树是完全相等的嘛
func isSameTree(_ p: TreeNode?, _ q: TreeNode?) -> Bool {
    guard let pNode = p ,let qNode = q else { return q == nil && p == nil }
    return pNode.val == qNode.val && isSameTree(pNode.left, qNode.left) && isSameTree(pNode.right, qNode.right)
}

斐波拉契数列

//剑指 Offer 10- I. 斐波那契数列
func fib(_ n: Int) -> Int {
    guard n > 1 else {
        return n
    }
     var first = 0
     var second = 1
     for _ in 0..<n-1 {
        let temp = first
        first = second
        second = temp + second
        second  %= 1000000007//答案需要取模 1e9+71000000007)
     }
    return second
}

反转字符串

//leetCode 第344题. 反转字符串
func reverseString(_ s: inout [Character]) {
    guard s.count > 1 else {
        return 
    }
    var i = 0
    var j = s.count - 1
    while i<j {
      let temp = s[i]
      s[i] = s[j]
      s[j] = temp
      i += 1
      j -= 1
    }
    
}

合并两个有序数组

//合并两个有序数组 leetcode 88 题
func merge(_ nums1: inout [Int], _ m: Int, _ nums2: [Int], _ n: Int) {
    
    var mr = m - 1
    var nr = n - 1
    
    while nr >= 0 {
        if mr >= 0 && nums1[mr] > nums2[nr]{//从最后开始赋值找最大的
            nums1[mr + nr + 1] = nums1[mr]
            mr -= 1
        } else {
            nums1[mr + nr + 1] = nums2[nr]
            nr -= 1
        }
    }
    
  }