剑指Offer-Swift

题目一:找出数组中的所有重复数字

在一个长度为n的数组里所有元素都在0~n-1的范围内。数组中某些数字是重复的,但不知道有几个数字是重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。例如:如果输入长度为7的数组 [2,3,1,0,2,5,3],那么对应输出是 2、3

func duplicate (_ numbers:[Int]?, _ duplicate: inout [Int]) -> Bool {
    
    guard var temps = numbers else {
        return false
    }
    
    guard temps.count >= 0 else {
        return false
    }
    
    for number in temps {
        
        if (number < 0 || number > temps.count - 1) {
            return false
        }
 
    }
    
    for (index, _) in temps.enumerated() {
        while temps[index] != index {
            if (temps[index] == temps[temps[index]]){
                duplicate.append(temps[index])
                break
            }
            //交换temps[index] 和 temps[temps[index]]
            let temp = temps[index]
            temps[index] = temps[temps[index]]
            temps[temp] = temp
        }
    }
    
    if (duplicate.count > 0) {
        return true
    }
    
    return false
}

上述的时间复杂度为O(n),需要使用O(n)的辅助空间

题目二:在二维数组中查找

在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。

func find(_ numbers:[[Int]]?, number: Int) -> Bool {
    
    guard var temps = numbers else {
        return false
    }
    
    guard temps.count > 0 else {
        return false
    }
    
    var row = 0
    var column = temps[0].count - 1
    
    while row < temps.count && column > 0 {
        
        if temps[row][column] == number {
            return true
        }else if temps[row][column] > number {
            column -= 1
        }else {
            row += 1
        }
        
    }
    
    return false
}

题目三:Swift实现链表及常用方法

class ListNode {
    var value: Int
    var next: ListNode?
    
    init(_ value: Int) {
        self.value = value
        self.next = nil
    }
}

class List {
    
    var head: ListNode?
    var tail: ListNode?
    
    func addToTail(_ value: Int) {
        let node = ListNode(value)
        
        if self.tail == nil {
            self.tail = node
            self.head = self.tail
        }else {
            self.tail!.next = node
            self.tail = self.tail!.next
        }
        
    }
    
    func addToHead(_ value: Int) {
        let node = ListNode(value)
        
        if self.head == nil {
            self.head = node
            self.tail = self.head
        }else {
            node.next = self.head
            self.head = node
        }
        
    }
    
    func removeNode(_ value: Int) {
        guard let head = self.head, let _ = self.tail else {
            return
        }
        
        var node = head
        while node.next != nil && node.next!.value != value{
            node = node.next!
        }
        
        if (node.next != nil && node.next!.value != value) {
            var temp = node.next
            node.next = node.next!.next
            
            if (temp != nil) {
                temp = nil
            }
        }
    }
    //从尾到头遍历链表 (递归实现,但可能导致栈溢出)
    func reverseTraverse(pHead:ListNode?) {
        
        guard let head = pHead else {
            return
        }
        
        if (head.next != nil) {
            reverseTraverse(pHead: head.next)
        }
        
        print(head.value)
    }
}

1.删除链表中倒数第n个节点。例:1->2->3->4->5,n = 2。返回1->2->3->5。

func removeNodeFromEnd(_ head: ListNode?, _ n: Int) -> ListNode? {
  guard let head = head else {
    return nil
  }
  
  let dummy = ListNode(0)
  dummy.next = head
  var pre: ListNode? = dummy
  var post: ListNode? = dummy
  
  // 设置后一个节点初始位置
  for _ in 0 ..< n {
    if post == nil {
      break
    }
    post = post!.next
  }
  
  // 同时移动前后节点
  while post != nil && post!.next != nil {
    pre = prev!.next
    post = post!.next
  }
  
  // 删除节点
  pre!.next = pre!.next!.next
  
  return dummy.next
}

题目四:斐波那契数列

求斐波那契数列的第n项

通常使用递归实现,但递归重复计算太多,效率太低

func fibonacci (_ n: Int) -> Int64 {
    
    let result:[Int64] = [0, 1]
    if (n < 2) {
        return result[n]
    }
    
    var fibNMinusOne: Int64 = 1
    var fibNMinusTwo: Int64 = 0
    var fibN: Int64 = 0xx
    
    for _ in 2...n {
        fibN = fibNMinusOne + fibNMinusTwo
        fibNMinusTwo = fibNMinusOne
        fibNMinusOne = fibN
    }
    
    return fibN
}

题目五:排序

1.快速排序

func partition(numbers: inout [Int], start: inout Int, end: inout Int) {
    
    let key = numbers[end]
    
    while start < end {
        
        while start < end && numbers[start] <= key {
            start += 1
        }
        numbers[end] = numbers[start]
        while start < end && numbers[end] >= key {
            end -= 1
        }
        numbers[start] = numbers[end]
    }
    
    numbers[start] = key
}

时间复杂度最坏情况:O(n^2)
平均:O(nlogn)

2.冒泡排序

func bubbleSort (numbers: inout [Int]) {
    let lenght = numbers.count
    
    for i in 0..

时间复杂度O(n^2)

3.插入排序

func insertSort(_ arr:inout [T], compare:(T, T) -> Bool) {
    for i in 1..= 0 && compare(arr[j], key) {
            arr[j + 1] = arr[j]
            j -= 1
        }
        arr[j + 1] = key
    }
}

时间复杂度O(n^2)

题目六:查找算法

1.二分查找(找到返回下标,未找到返回-1)

func binarySearch (_ numbers: [Int], number: Int) -> Int {
    
    var left = 0
    var right = numbers.count - 1
    
    while left <= right {
        let mid = (left + right) / 2
        
        if (numbers[mid] > number) {
            right = mid - 1
        }else if (numbers[mid] < number) {
            left = mid + 1
        }else {
            return mid
        }
    }
    
    return -1
}

题目七:回溯法

1.地上有一个m行n列的方格。一个机器人从坐标(0,0)的格子开始移动,它每次可以向左、右、上、下移动一格,但不能进入行坐标和列坐标的数位之和大于k的格子。例如:当k为18时,机器人能够进入方格(35, 37),因为3+5+3+7=18,但它不能进入方格(35,38),因为3+5+3+8=19 。请问该机器人能够到达多少个格子?

func movingCount(threshold: Int, rows:Int, cols:Int) -> Int {
    
    guard threshold >= 0, rows > 0, cols > 0 else {
        return 0
    }
    var visited = Array(repeating: false, count: rows * cols)
    
    let count = movingCountCore(threshold, rows, cols, 0, 0, &visited)
    
    return count
}

func movingCountCore(_ threshold: Int,_ rows:Int,_ cols:Int,_ row:Int,_ col:Int,_ visited: inout [Bool]) -> Int {
    var count = 0
    
    if check(threshold: threshold, rows: rows, cols: cols, row: row, col: col, visited: visited) {
        visited[row * cols + col] = true
        
        count = 1 + movingCountCore(threshold, rows, cols, row - 1, col, &visited)
            + movingCountCore(threshold, rows, cols, row, col - 1, &visited)
            + movingCountCore(threshold, rows, cols, row + 1, col, &visited)
            + movingCountCore(threshold, rows, cols, row, col + 1, &visited)
        
    }
    
    return count
}

func check (threshold: Int, rows:Int, cols:Int, row:Int, col:Int, visited: [Bool]) -> Bool {
    
    if row >= 0 && row < rows && col < cols && getDigitSum(row) + getDigitSum(col) <= threshold && !visited[row*cols + col] {
        return true
    }
    
    return false
}

func getDigitSum(_ number: Int) -> Int {
    
    var temp = number
    var sum = 0
    
    while temp < 0 {
        sum += number % 10
        temp = temp / 10
    }
    return sum
}

题目八

1、给你一根长度为n的绳子,请把绳子剪成m段(n、m都是整数,n > 1、m > 1),每段绳子的长度记为k[0]、k[1]、k[2]...k[m]。请问k[0] x k[1] x k[2]...x k[m]可能的最大乘积是多少?例如,当绳子长度为8时,我们把它剪成2、3、3三段,得到最大的乘积为18

贪婪算法

func maxProductAfterCutting(length: Int) -> Int {
    if length < 2 {
        return 0
    }
    
    if length == 2 {
        return 1
    }
    
    if length == 3 {
        return 2
    }
    
    var timeOf3 = length / 3
    
    if length - timeOf3 * 3 == 1 {
        timeOf3 -= 1
    }
    
    let timeOf2 = (length - timeOf3 * 3) / 2
    
    let n = powf(Float(3), Float(timeOf3))
    let m = powf(Float(2), Float(timeOf2))
    
    return Int(n * m)
}

证明:当n >= 5时可以证明 3(n - 3) > n 并且 2(n -2) > n 也就是说当n大于或等于5的时候,要把绳子剪成3或者2的绳子段,又因为 3(n - 3) > 2(n -2) 成立,所以应该尽可能多的剪成3,当n为4时因为至少剪一刀,所以乘积最大为2*2

时间和空间复杂度O(1)

题目九 按位运算

1.计算一个数的二进制中有多少个1


func numberOfOne(_ number:Int) -> Int {
    
    var (n, count) = (number, 0)
    
    while n > 0 {
        count += 1
        n = (n - 1) & n
    }
    return count
}

题目十 数值的整数次方


enum PowerError: Error {
    case invalidInput
}


func power(base: Double, exponent:Int) throws -> Double {
    
    if base == 0.0 && exponent < 0 {
        throw PowerError.invalidInput
    }
    
    var absExponent = exponent
    
    if exponent < 0 {
        absExponent = -exponent
    }
    
    var result = powerWithUnsignedExponent(base: base, exponent: absExponent)
    if exponent < 0 {
        result = 1.0 / result
    }
    return result
}

func powerWithUnsignedExponent(base: Double, exponent: Int) -> Double {
    
    if exponent == 0 {
        return 1
    }
    if (exponent == 1) {
        return base
    }
    
    var result = powerWithUnsignedExponent(base: base, exponent: exponent >> 1)
    result *= result
    
    if exponent & 0x1 == 1 {
        result *= base
    }
    
    return result
}

题目十一


func Reorder(numbers: inout [T],_ conditions:(T) ->Bool) {
    
    if numbers.count <= 0 {
        return
    }
    
    var (start, end) = (0, numbers.count - 1)
    
    while start < end {
        
        while start < end && !conditions(numbers[start]) {
            start += 1
        }
        
        while start < end && conditions(numbers[end]) {
            end -= 1
        }
        
        if start < end {
            let temp = numbers[start]
            numbers[start] = numbers[end]
            numbers[end] = temp
        }
        
    }
    
}

Reorder(numbers: &arr) { (number:Int) -> Bool in
    return (number & 1) == 0
}

题目十二 查找链表中倒数第k个节点


func findKthToTail(listHeadNode: ListNode, k:Int) -> ListNode? {
    
    var pAhead = listHeadNode
    
    for _ in 0..

题目十三 合并两个有序递增链表,合并后链表依然有序递增。

class ListNode {
    var value: Int
    var next: ListNode?

    init(_ value: Int) {
        self.value = value
        self.next = nil
    }
}

func Merge(pHead1: ListNode?, pHead2: ListNode?) -> ListNode? {
    
    guard let pHeadOne = pHead1, let pHeadTwo = pHead2 else {
        return nil
    }
    
    var pMergedHead: ListNode? = nil
    
    if (pHeadOne.value < pHeadTwo.value) {
        pMergedHead = pHeadOne
        pMergedHead?.next = Merge(pHead1: pHeadOne.next, pHead2: pHeadTwo)
    }else {
        pMergedHead = pHeadTwo
        pMergedHead?.next = Merge(pHead1: pHeadOne, pHead2: pHeadTwo.next)
    }
    
    return pMergedHead
}

你可能感兴趣的:(剑指Offer-Swift)