劍指Offer-Swift

題目一:找出數(shù)組中的所有重復(fù)數(shù)字

在一個(gè)長(zhǎng)度為n的數(shù)組里所有元素都在0~n-1的范圍內(nèi)。數(shù)組中某些數(shù)字是重復(fù)的,但不知道有幾個(gè)數(shù)字是重復(fù)了,也不知道每個(gè)數(shù)字重復(fù)了幾次。請(qǐng)找出數(shù)組中任意一個(gè)重復(fù)的數(shù)字。例如:如果輸入長(zhǎng)度為7的數(shù)組 [2,3,1,0,2,5,3],那么對(duì)應(yīng)輸出是 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
}

上述的時(shí)間復(fù)雜度為O(n),需要使用O(n)的輔助空間

題目二:在二維數(shù)組中查找

在一個(gè)二維數(shù)組中,每一行都按照從左到右遞增的順序排序,每一列都按照從上到下遞增的順序排序。請(qǐng)完成一個(gè)函數(shù),輸入這樣的一個(gè)二維數(shù)組和一個(gè)整數(shù),判斷數(shù)組中是否含有該整數(shù)。

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實(shí)現(xiàn)鏈表及常用方法

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
            }
        }
    }
    //從尾到頭遍歷鏈表 (遞歸實(shí)現(xiàn),但可能導(dǎo)致棧溢出)
    func reverseTraverse(pHead:ListNode?) {
        
        guard let head = pHead else {
            return
        }
        
        if (head.next != nil) {
            reverseTraverse(pHead: head.next)
        }
        
        print(head.value)
    }
}

1.刪除鏈表中倒數(shù)第n個(gè)節(jié)點(diǎ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
  
  // 設(shè)置后一個(gè)節(jié)點(diǎn)初始位置
  for _ in 0 ..< n {
    if post == nil {
      break
    }
    post = post!.next
  }
  
  // 同時(shí)移動(dòng)前后節(jié)點(diǎn)
  while post != nil && post!.next != nil {
    pre = prev!.next
    post = post!.next
  }
  
  // 刪除節(jié)點(diǎn)
  pre!.next = pre!.next!.next
  
  return dummy.next
}

題目四:斐波那契數(shù)列

求斐波那契數(shù)列的第n項(xiàng)

通常使用遞歸實(shí)現(xiàn),但遞歸重復(fù)計(jì)算太多,效率太低

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
}

時(shí)間復(fù)雜度最壞情況:O(n^2)
平均:O(nlogn)

2.冒泡排序

func bubbleSort (numbers: inout [Int]) {
    let lenght = numbers.count
    
    for i in 0..<lenght - 1 {
        
        for j in 0..<lenght - 1 - i {
            
            if (numbers[j] < numbers[j + 1]) {
                let temp = numbers[j]
                numbers[j] = numbers[j + 1]
                numbers[j + 1] = temp
            }
        }
    }
}

時(shí)間復(fù)雜度O(n^2)

3.插入排序

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

時(shí)間復(fù)雜度O(n^2)

題目六:查找算法

1.二分查找(找到返回下標(biāo),未找到返回-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.地上有一個(gè)m行n列的方格。一個(gè)機(jī)器人從坐標(biāo)(0,0)的格子開(kāi)始移動(dòng),它每次可以向左、右、上、下移動(dòng)一格,但不能進(jìn)入行坐標(biāo)和列坐標(biāo)的數(shù)位之和大于k的格子。例如:當(dāng)k為18時(shí),機(jī)器人能夠進(jìn)入方格(35, 37),因?yàn)?+5+3+7=18,但它不能進(jìn)入方格(35,38),因?yàn)?+5+3+8=19 。請(qǐng)問(wèn)該機(jī)器人能夠到達(dá)多少個(gè)格子?

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、給你一根長(zhǎng)度為n的繩子,請(qǐng)把繩子剪成m段(n、m都是整數(shù),n > 1、m > 1),每段繩子的長(zhǎng)度記為k[0]、k[1]、k[2]...k[m]。請(qǐng)問(wèn)k[0] x k[1] x k[2]...x k[m]可能的最大乘積是多少?例如,當(dāng)繩子長(zhǎng)度為8時(shí),我們把它剪成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)
}

證明:當(dāng)n >= 5時(shí)可以證明 3(n - 3) > n 并且 2(n -2) > n 也就是說(shuō)當(dāng)n大于或等于5的時(shí)候,要把繩子剪成3或者2的繩子段,又因?yàn)?3(n - 3) > 2(n -2) 成立,所以應(yīng)該盡可能多的剪成3,當(dāng)n為4時(shí)因?yàn)橹辽偌粢坏叮猿朔e最大為2*2

時(shí)間和空間復(fù)雜度O(1)

題目九 按位運(yùn)算

1.計(jì)算一個(gè)數(shù)的二進(jìn)制中有多少個(gè)1


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

題目十 數(shù)值的整數(shù)次方


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<T>(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
}

題目十二 查找鏈表中倒數(shù)第k個(gè)節(jié)點(diǎn)


func findKthToTail(listHeadNode: ListNode, k:Int) -> ListNode? {
    
    var pAhead = listHeadNode
    
    for _ in 0..<k {
        
        if pAhead.next != nil {
           pAhead = pAhead.next!
        }else {
            return nil
        }
    }
    
    var pBehind = listHeadNode
    
    while pAhead.next != nil {
        
        pAhead = pAhead.next!
        pBehind = pBehind.next!
        
    }
    
    return pBehind
}

題目十三 合并兩個(gè)有序遞增鏈表,合并后鏈表依然有序遞增。

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
}

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容