├── .gitignore ├── 03_01_DuplicationInArray.playground ├── Contents.swift └── contents.xcplayground ├── 03_02_DuplicationInArrayNoEdit.playground ├── Contents.swift └── contents.xcplayground ├── 04_FindInPartiallySortedMatrix.playground ├── Contents.swift └── contents.xcplayground ├── 05_ReplaceSpaces.playground ├── Contents.swift └── contents.xcplayground ├── 06_PrintListInReversedOrder.playground ├── Contents.swift └── contents.xcplayground ├── 07_ ConstructBinaryTree.playground ├── Contents.swift └── contents.xcplayground ├── 08_NextNodeInBinaryTrees.playground ├── Contents.swift └── contents.xcplayground ├── 09_QueueWithTwoStacks.playground ├── Contents.swift └── contents.xcplayground ├── 10_Fibonacci.playground ├── Contents.swift └── contents.xcplayground ├── 11_MinNumberInRotatedArray.playground ├── Contents.swift └── contents.xcplayground ├── 12_StringPathInMatrix.playground ├── Contents.swift └── contents.xcplayground ├── 13_RobotMove.playground ├── Contents.swift └── contents.xcplayground ├── 14_CuttingRope.playground ├── Contents.swift └── contents.xcplayground ├── 15_NumberOf1InBinary.playground ├── Contents.swift └── contents.xcplayground ├── 16_Power.playground ├── Contents.swift └── contents.xcplayground ├── 17_Print1ToMaxOfNDigits.playground ├── Contents.swift └── contents.xcplayground ├── 18_01_DeleteNodeInList.playground ├── Contents.swift └── contents.xcplayground ├── 18_02_DeleteDuplicatedNode.playground ├── Contents.swift └── contents.xcplayground ├── 19_RegularExpressionsMatching.playground ├── Contents.swift └── contents.xcplayground ├── 20_NumericStrings.playground ├── Contents.swift └── contents.xcplayground ├── 21_ReorderArray.playground ├── Contents.swift └── contents.xcplayground ├── 22_KthNodeFromEnd.playground ├── Contents.swift └── contents.xcplayground ├── 23_EntryNodeInListLoop.playground ├── Contents.swift └── contents.xcplayground ├── 24_ReverseList.playground ├── Contents.swift └── contents.xcplayground ├── 25_MergeSortedLists.playground ├── Contents.swift └── contents.xcplayground ├── 26_SubstructureInTree.playground ├── Contents.swift └── contents.xcplayground ├── 27_MirrorOfBinaryTree.playground ├── Contents.swift └── contents.xcplayground ├── 28_SymmetricalBinaryTree.playground ├── Contents.swift └── contents.xcplayground ├── 29_PrintMatrix.playground ├── Contents.swift └── contents.xcplayground ├── 30_MinInStack.playground ├── Contents.swift └── contents.xcplayground ├── 31_StackPushPopOrder.playground ├── Contents.swift └── contents.xcplayground ├── 32_01_PrintTreeFromTopToBottom.playground ├── Contents.swift └── contents.xcplayground ├── 32_02_PrintTreesInLines.playground.playground ├── Contents.swift └── contents.xcplayground ├── 32_03_PrintTreesInZigzag.playground ├── Contents.swift └── contents.xcplayground ├── 33_SquenceOfBST.playground ├── Contents.swift └── contents.xcplayground ├── 34_PathInTree.playground ├── Contents.swift └── contents.xcplayground ├── 35_CopyComplexList.playground ├── Contents.swift └── contents.xcplayground ├── 36_ConvertBinarySearchTree.playground ├── Contents.swift └── contents.xcplayground ├── 37_SerializeBinaryTrees.playground ├── Contents.swift └── contents.xcplayground ├── 38_StringPermutation.playground ├── Contents.swift └── contents.xcplayground ├── 39_MoreThanHalfNumber.playground ├── Contents.swift └── contents.xcplayground ├── 40_KLeastNumbers.playground ├── Contents.swift ├── Sources │ └── Heap.swift └── contents.xcplayground ├── 41_StreamMedian.playground ├── Contents.swift ├── Sources │ └── Heap.swift └── contents.xcplayground ├── 42_GreatestSumOfSubarrays.playground ├── Contents.swift └── contents.xcplayground ├── 43_NumberOf1.playground ├── Contents.swift └── contents.xcplayground ├── 44_DigitsInSequence.playground ├── Contents.swift └── contents.xcplayground ├── 45_SortArrayForMinNumber.playground ├── Contents.swift └── contents.xcplayground ├── 46_TranslateNumbersToStrings.playground ├── Contents.swift └── contents.xcplayground ├── 47_MaxValueOfGifts.playground ├── Contents.swift └── contents.xcplayground ├── 48_LongestSubstringWithoutDup.playground ├── Contents.swift └── contents.xcplayground ├── 49_UglyNumber.playground ├── Contents.swift └── contents.xcplayground ├── 50_01_FirstNotRepeatingChar.playground ├── Contents.swift └── contents.xcplayground ├── 50_02_FirstCharacterInStream.playground ├── Contents.swift └── contents.xcplayground ├── 51_InversePairs.playground ├── Contents.swift └── contents.xcplayground ├── 52_FirstCommonNodesInLists.playground ├── Contents.swift ├── Sources │ └── ListNode.swift └── contents.xcplayground ├── 53_01_NumberOfK.playground ├── Contents.swift └── contents.xcplayground ├── 53_02_MissingNumber.playground ├── Contents.swift └── contents.xcplayground ├── 53_03_IntegerIdenticalToIndex.playground ├── Contents.swift └── contents.xcplayground ├── 54_KthNodeInBST.playground ├── Contents.swift └── contents.xcplayground ├── 55_01_TreeDepth.playground ├── Contents.swift └── contents.xcplayground ├── 55_02_BalancedBinaryTree.playground ├── Contents.swift └── contents.xcplayground ├── 56_01_NumbersAppearOnce.playground ├── Contents.swift └── contents.xcplayground ├── 56_02_NumberAppearingOnce.playground ├── Contents.swift └── contents.xcplayground ├── 57_01_TwoNumbersWithSum.playground ├── Contents.swift └── contents.xcplayground ├── 57_02_ContinuousSquenceWithSum.playground ├── Contents.swift └── contents.xcplayground ├── 58_01_ReverseWordsInSentence.playground ├── Contents.swift └── contents.xcplayground ├── 58_02_LeftRotateString.playground ├── Contents.swift └── contents.xcplayground ├── 59_01_MaxInSlidingWindow.playground ├── Contents.swift └── contents.xcplayground ├── 59_02_QueueWithMax.playground ├── Contents.swift └── contents.xcplayground ├── 60_DicesProbability.playground ├── Contents.swift └── contents.xcplayground ├── 61_ContinousCards.playground ├── Contents.swift └── contents.xcplayground ├── 62_LastNumberInCircle.playground ├── Contents.swift └── contents.xcplayground ├── 63_MaximalProfit.playground ├── Contents.swift └── contents.xcplayground ├── 64_Accumulate.playground ├── Contents.swift └── contents.xcplayground ├── 65_AddTwoNumbers.playground ├── Contents.swift └── contents.xcplayground ├── 66_ConstuctArray.playground ├── Contents.swift └── contents.xcplayground ├── 67_StringToInt.playground ├── Contents.swift └── contents.xcplayground ├── 68_CommonParentInTree.playground ├── Contents.swift └── contents.xcplayground └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData/ 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata/ 19 | 20 | ## Other 21 | *.moved-aside 22 | *.xccheckout 23 | *.xcscmblueprint 24 | 25 | ## Obj-C/Swift specific 26 | *.hmap 27 | *.ipa 28 | *.dSYM.zip 29 | *.dSYM 30 | 31 | ## Playgrounds 32 | timeline.xctimeline 33 | playground.xcworkspace 34 | 35 | # Swift Package Manager 36 | # 37 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 38 | # Packages/ 39 | # Package.pins 40 | # Package.resolved 41 | .build/ 42 | 43 | # CocoaPods 44 | # 45 | # We recommend against adding the Pods directory to your .gitignore. However 46 | # you should judge for yourself, the pros and cons are mentioned at: 47 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 48 | # 49 | # Pods/ 50 | 51 | # Carthage 52 | # 53 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 54 | # Carthage/Checkouts 55 | 56 | Carthage/Build 57 | 58 | # fastlane 59 | # 60 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 61 | # screenshots whenever they are needed. 62 | # For more information about the recommended setup visit: 63 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 64 | 65 | fastlane/report.xml 66 | fastlane/Preview.html 67 | fastlane/screenshots/**/*.png 68 | fastlane/test_output 69 | -------------------------------------------------------------------------------- /03_01_DuplicationInArray.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | //================================================================== 2 | // 《剑指Offer——名企面试官精讲典型编程题》代码 3 | //================================================================== 4 | // 面试题3(一):找出数组中重复的数字 5 | // 题目:在一个长度为n的数组里的所有数字都在0到n-1的范围内。数组中某些数字是重复的,但不知道有几个数字重复了, 6 | // 也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。例如,如果输入长度为7的数组{2, 3, 1, 0, 2, 5, 3}, 7 | // 那么对应的输出是重复的数字2或者3。 8 | 9 | import Foundation 10 | import XCTest 11 | 12 | class Solution { 13 | /** 14 | 查找整数数组中任一重复的数字 15 | - Parameters: 16 | - nums: 整数数组 17 | - Returns: Tuple(重复数字的索引,值) 18 | */ 19 | func duplicate(_ nums: [Int]) -> (index: Int, num: Int)? { 20 | var nums = nums 21 | for index in 0.. 2 | 3 | 4 | -------------------------------------------------------------------------------- /03_02_DuplicationInArrayNoEdit.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | //================================================================== 2 | // 《剑指Offer——名企面试官精讲典型编程题》代码 3 | //================================================================== 4 | // 面试题3(二):不修改数组找出重复的数字 5 | // 题目:在一个长度为n+1的数组里的所有数字都在1到n的范围内,所以数组中至 6 | // 少有一个数字是重复的。请找出数组中任意一个重复的数字,但不能修改输入的 7 | // 数组。例如,如果输入长度为8的数组{2, 3, 5, 4, 3, 2, 6, 7},那么对应的 8 | // 输出是重复的数字2或者3。 9 | 10 | import Foundation 11 | import XCTest 12 | 13 | class Solution { 14 | /** 15 | 查找整数数组中任一重复的数字 16 | - Parameters: 17 | - nums: 整数数组 18 | - Returns: 重复的整数 19 | */ 20 | func duplicate(_ nums: [Int]) -> Int? { 21 | // 所有数字都在1到 nums.count-1 大小范围内, min 和 max 表示这个范围 22 | var min = 1 23 | var max = nums.count - 1 24 | while min <= max { 25 | let middle = (max - min) / 2 + min 26 | let countAtRange = nums.filter { $0 >= min && $0 <= middle }.count 27 | if min == max { 28 | if countAtRange > 1 { 29 | return min 30 | } else { 31 | break 32 | } 33 | } 34 | let expectCount = middle - min + 1 35 | if countAtRange > expectCount { 36 | max = middle 37 | } else { 38 | min = middle + 1 39 | } 40 | } 41 | return nil 42 | } 43 | } 44 | 45 | class UnitTests: XCTestCase { 46 | var solution: Solution! 47 | 48 | override func setUp() { 49 | super.setUp() 50 | solution = Solution() 51 | } 52 | ///数组中存在多个重复的数字 53 | func testCase1() { 54 | let nums = [2, 3, 5, 4, 3, 2, 6, 7] 55 | let duplications = [2,3] 56 | XCTAssertTrue(duplications.contains(solution.duplicate(nums)!)) 57 | } 58 | ///数组中存在一个重复的数字 59 | func testCase2() { 60 | let nums = [3, 2, 1, 4, 4, 5, 6, 7] 61 | XCTAssertEqual(solution.duplicate(nums)!, 4) 62 | } 63 | ///重复数字是数组中最小的数字 64 | func testCase3() { 65 | let nums = [1, 2, 3, 4, 5, 6, 7, 1, 8] 66 | XCTAssertEqual(solution.duplicate(nums)!, 1) 67 | } 68 | ///重复数字是数组中最大的数字 69 | func testCase4() { 70 | let nums = [1, 7, 3, 4, 5, 6, 8, 2, 8] 71 | XCTAssertEqual(solution.duplicate(nums)!, 8) 72 | } 73 | ///数组中只有两个数字 74 | func testCase5() { 75 | let nums = [1, 1] 76 | XCTAssertEqual(solution.duplicate(nums)!, 1) 77 | } 78 | ///一个数字重复三次 79 | func testCase6() { 80 | let nums = [1, 2, 2, 6, 4, 5, 2] 81 | XCTAssertEqual(solution.duplicate(nums)!, 2) 82 | } 83 | ///数组中不存在重复的数字 84 | func testCase7() { 85 | let nums = [1, 2, 6, 4, 5, 3] 86 | XCTAssertNil(solution.duplicate(nums)) 87 | } 88 | ///无效输入 89 | func testCase8() { 90 | let nums:[Int] = [] 91 | XCTAssertNil(solution.duplicate(nums)) 92 | } 93 | } 94 | 95 | UnitTests.defaultTestSuite.run() 96 | -------------------------------------------------------------------------------- /03_02_DuplicationInArrayNoEdit.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /04_FindInPartiallySortedMatrix.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | //================================================================== 2 | // 《剑指Offer——名企面试官精讲典型编程题》代码 3 | //================================================================== 4 | // 面试题4:二维数组中的查找 5 | // 题目:在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按 6 | // 照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个 7 | // 整数,判断数组中是否含有该整数。 8 | 9 | import Foundation 10 | import XCTest 11 | 12 | class Solution { 13 | /** 14 | 判断二维数组中是否含有该整数P 15 | 从二维数组的右上角开始查找 16 | - Parameters: 17 | - matrix: 二维数组 18 | - num: 查找的整数 19 | - Returns: 是否包含 20 | */ 21 | func find(_ matrix: [[Int]], num: Int) -> Bool { 22 | // y 表示二维数组的列数, x 表示二维数组的行数 索引均从 0 开始 23 | // 查找方法从二维数组的右上角开始比较 24 | var y = 0 25 | var x = matrix.count - 1 26 | while y <= matrix[0].count - 1 && x >= 0 { 27 | if matrix[y][x] > num { 28 | x -= 1 29 | } else if matrix[y][x] < num { 30 | y += 1 31 | } else { 32 | return true 33 | } 34 | } 35 | return false 36 | } 37 | } 38 | 39 | class UnitTests: XCTestCase { 40 | var solution: Solution! 41 | override func setUp() { 42 | super.setUp() 43 | solution = Solution() 44 | } 45 | 46 | // 1 2 8 9 47 | // 2 4 9 12 48 | // 4 7 10 13 49 | // 6 8 11 15 50 | // 查找的数在数组中 51 | func testCate1(){ 52 | let matrix = [[1, 2, 8, 9],[2, 4, 9, 12],[4, 7, 10, 13],[6, 8, 11, 15]] 53 | XCTAssertTrue(solution.find(matrix, num: 7)) 54 | } 55 | 56 | // 1 2 8 9 57 | // 2 4 9 12 58 | // 4 7 10 13 59 | // 6 8 11 15 60 | // 要查找的数不在数组中 61 | func testCate2(){ 62 | let matrix = [[1, 2, 8, 9],[2, 4, 9, 12],[4, 7, 10, 13],[6, 8, 11, 15]] 63 | XCTAssertFalse(solution.find(matrix, num: 5)) 64 | } 65 | 66 | // 1 2 8 9 67 | // 2 4 9 12 68 | // 4 7 10 13 69 | // 6 8 11 15 70 | // 要查找的数是数组中最小的数字 71 | func testCate3(){ 72 | let matrix = [[1, 2, 8, 9],[2, 4, 9, 12],[4, 7, 10, 13],[6, 8, 11, 15]] 73 | XCTAssertTrue(solution.find(matrix, num: 1)) 74 | } 75 | 76 | // 1 2 8 9 77 | // 2 4 9 12 78 | // 4 7 10 13 79 | // 6 8 11 15 80 | // 要查找的数是数组中最大的数字 81 | func testCate4(){ 82 | let matrix = [[1, 2, 8, 9],[2, 4, 9, 12],[4, 7, 10, 13],[6, 8, 11, 15]] 83 | XCTAssertTrue(solution.find(matrix, num: 15)) 84 | } 85 | 86 | // 1 2 8 9 87 | // 2 4 9 12 88 | // 4 7 10 13 89 | // 6 8 11 15 90 | // 要查找的数比数组中最小的还要小 91 | func testCate5(){ 92 | let matrix = [[1, 2, 8, 9],[2, 4, 9, 12],[4, 7, 10, 13],[6, 8, 11, 15]] 93 | XCTAssertFalse(solution.find(matrix, num: 0)) 94 | } 95 | 96 | // 1 2 8 9 97 | // 2 4 9 12 98 | // 4 7 10 13 99 | // 6 8 11 15 100 | // 要查找的数比数组中最大的还要大 101 | func testCate6(){ 102 | let matrix = [[1, 2, 8, 9],[2, 4, 9, 12],[4, 7, 10, 13],[6, 8, 11, 15]] 103 | XCTAssertFalse(solution.find(matrix, num: 16)) 104 | } 105 | } 106 | 107 | UnitTests.defaultTestSuite.run() 108 | -------------------------------------------------------------------------------- /04_FindInPartiallySortedMatrix.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /05_ReplaceSpaces.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | //================================================================== 2 | // 《剑指Offer——名企面试官精讲典型编程题》代码 3 | //================================================================== 4 | // 面试题5:替换空格 5 | // 题目:请实现一个函数,把字符串中的每个空格替换成"%20"。例如输入“We are happy.”, 6 | // 则输出“We%20are%20happy.” 7 | 8 | // 用swift来做这道题目感觉怪怪的😓 9 | // 本意是要求在时间复杂度O(n)下完成 10 | // 方法是先查找出所有的空格,计算出替换之后字符串的长度L,然后在原字符串L处开始从尾到头进行替换 11 | 12 | import Foundation 13 | import XCTest 14 | 15 | class Solution { 16 | /** 17 | - Parameters: 18 | - charArray 输入的字符数组 19 | - Returns: 替换之后的字符数组 20 | */ 21 | func replace(_ charArray: [Character]) -> [Character] { 22 | /// TODO 23 | return charArray 24 | } 25 | } 26 | 27 | class UnitTests: XCTestCase { 28 | var solution: Solution! 29 | 30 | override func setUp() { 31 | super.setUp() 32 | solution = Solution() 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /05_ReplaceSpaces.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /06_PrintListInReversedOrder.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | //================================================================== 2 | // 《剑指Offer——名企面试官精讲典型编程题》代码 3 | //================================================================== 4 | // 面试题6:从尾到头打印链表 5 | // 题目:输入一个链表的头结点,从尾到头反过来打印出每个结点的值。 6 | 7 | // 本代码解法,使用一个栈存储各个节点 😓, 再反向打印 8 | // 其他解法: 比如递归调用,或者修改链表 9 | 10 | import Foundation 11 | import XCTest 12 | 13 | class ListNode { 14 | var next: ListNode? 15 | var value: Int 16 | init(value: Int, next: ListNode?) { 17 | self.value = value 18 | self.next = next 19 | } 20 | } 21 | 22 | class Solution { 23 | /** 24 | 从尾到头打印链表 25 | - Parameters: 26 | - listnode: 头结点 27 | - Returns: 28 | */ 29 | func reverseListNode(_ node: ListNode) -> [Int] { 30 | var nodes = [Int]() 31 | var currentNode:ListNode? = node 32 | while currentNode != nil { 33 | nodes.append(currentNode!.value) 34 | currentNode = currentNode!.next 35 | } 36 | return nodes.reversed() 37 | } 38 | } 39 | 40 | class UnitTests: XCTestCase { 41 | var solution: Solution! 42 | override func setUp() { 43 | super.setUp() 44 | solution = Solution() 45 | } 46 | 47 | /// 1->2->3->4->5 48 | func testCase1() { 49 | let node5 = ListNode(value: 5, next: nil) 50 | let node4 = ListNode(value: 4, next: node5) 51 | let node3 = ListNode(value: 3, next: node4) 52 | let node2 = ListNode(value: 2, next: node3) 53 | let node1 = ListNode(value: 1, next: node2) 54 | XCTAssertEqual(solution.reverseListNode(node1), [5,4,3,2,1]) 55 | } 56 | 57 | ///只有一个节点 1 58 | func testCase2() { 59 | let node1 = ListNode(value: 1, next: nil) 60 | XCTAssertEqual(solution.reverseListNode(node1), [1]) 61 | } 62 | } 63 | 64 | UnitTests.defaultTestSuite.run() 65 | -------------------------------------------------------------------------------- /06_PrintListInReversedOrder.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /07_ ConstructBinaryTree.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /08_NextNodeInBinaryTrees.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /09_QueueWithTwoStacks.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | //================================================================== 2 | // 《剑指Offer——名企面试官精讲典型编程题》代码 3 | //================================================================== 4 | // 面试题9:用两个栈实现队列 5 | // 题目:用两个栈实现一个队列。队列的声明如下,请实现它的两个函数appendTail 6 | // 和deleteHead,分别完成在队列尾部插入结点和在队列头部删除结点的功能。 7 | // 8 | // 备注:使用array模拟stack,只用了数组的append和removeLast方法 9 | 10 | import Foundation 11 | import XCTest 12 | 13 | class MyQueue { 14 | private var array1 = [T]() 15 | private var array2 = [T]() 16 | 17 | /** 18 | 在队列末端添加元素 19 | - Parameters: 20 | - element:待添加的元素 21 | */ 22 | func appendTail(element: T) { 23 | array1.append(element) 24 | } 25 | /** 26 | 删除头节点 27 | - Returns: 被删除的头节点 28 | */ 29 | func deleteHead() -> T? { 30 | if array2.count > 0 { 31 | return array2.removeLast() 32 | } else { 33 | while array1.count > 0 { 34 | array2.append(array1.removeLast()) 35 | } 36 | if array2.count > 0 { 37 | return array2.removeLast() 38 | } else { 39 | return nil 40 | } 41 | } 42 | } 43 | 44 | } 45 | 46 | 47 | class UnitTests: XCTestCase { 48 | var queue: MyQueue! 49 | 50 | override func setUp(){ 51 | super.setUp() 52 | queue = MyQueue() 53 | } 54 | 55 | func testCase1() { 56 | queue.appendTail(element: 1) 57 | queue.appendTail(element: 2) 58 | queue.appendTail(element: 3) 59 | XCTAssertEqual(1, queue.deleteHead()!) 60 | XCTAssertEqual(2, queue.deleteHead()!) 61 | 62 | queue.appendTail(element: 4) 63 | XCTAssertEqual(3, queue.deleteHead()!) 64 | 65 | queue.appendTail(element: 5) 66 | XCTAssertEqual(4, queue.deleteHead()!) 67 | 68 | XCTAssertEqual(5, queue.deleteHead()!) 69 | } 70 | } 71 | 72 | UnitTests.defaultTestSuite.run() 73 | -------------------------------------------------------------------------------- /09_QueueWithTwoStacks.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /10_Fibonacci.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | //================================================================== 2 | // 《剑指Offer——名企面试官精讲典型编程题》代码 3 | //================================================================== 4 | // 面试题10:斐波那契数列 5 | // 题目:写一个函数,输入n,求斐波那契(Fibonacci)数列的第n项。 6 | 7 | import Foundation 8 | import XCTest 9 | 10 | class Solution { 11 | /** 12 | 求斐波那契数列中的第n个元素(递归方式-效率低) 13 | - Parameters: 14 | - n: n 15 | - Returns: 第n个斐波那契数列的值 16 | */ 17 | func recursion(_ n: Int) -> Int{ 18 | if n <= 0 { 19 | return 0 20 | } 21 | if n == 1 { 22 | return 1 23 | } 24 | return recursion(n - 1) + recursion(n - 2) 25 | } 26 | /** 27 | 求斐波那契数列中的第n个元素(循环方式-效率较高) 28 | - Parameters: 29 | - n: n 30 | - Returns: 第n个斐波那契数列的值 31 | */ 32 | func loop(_ n: Int) -> Int { 33 | if n <= 0 { 34 | return 0 35 | } 36 | if n == 1 { 37 | return 1 38 | } 39 | var num1 = 0 40 | var num2 = 1 41 | for _ in 2...n { 42 | let sum = num1 + num2 43 | num1 = num2 44 | num2 = sum 45 | } 46 | return num2 47 | } 48 | } 49 | 50 | 51 | class UnitTests: XCTestCase { 52 | var solution: Solution! 53 | 54 | override func setUp() { 55 | super.setUp() 56 | solution = Solution() 57 | } 58 | private func test(_ n: Int, expected: Int) { 59 | XCTAssertEqual(solution.loop(n), expected) 60 | XCTAssertEqual(solution.recursion(n), expected) 61 | } 62 | func testCase1() { 63 | test(0, expected: 0) 64 | test(1, expected: 1) 65 | test(2, expected: 1) 66 | test(3, expected: 2) 67 | test(4, expected: 3) 68 | test(5, expected: 5) 69 | test(6, expected: 8) 70 | test(7, expected: 13) 71 | test(8, expected: 21) 72 | test(9, expected: 34) 73 | test(10, expected: 55) 74 | test(20, expected: 6765) 75 | //再往上测试,通过递归的方式,电脑CPU就转的不行了😓 76 | } 77 | } 78 | 79 | UnitTests.defaultTestSuite.run() 80 | -------------------------------------------------------------------------------- /10_Fibonacci.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /11_MinNumberInRotatedArray.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | //================================================================== 2 | // 《剑指Offer——名企面试官精讲典型编程题》代码 3 | //================================================================== 4 | 5 | // 面试题11:旋转数组的最小数字 6 | // 题目:把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。 7 | // 输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。例如数组 8 | // {3, 4, 5, 1, 2}为{1, 2, 3, 4, 5}的一个旋转,该数组的最小值为1。 9 | 10 | import Foundation 11 | import XCTest 12 | 13 | class Solution { 14 | /** 15 | 旋转数组的最小数字 16 | - Parameters: 17 | - nums: 一个递增数组的旋转 18 | - Returns: 数组中最小的那个数字 19 | */ 20 | func Min(_ nums: [Int]) -> Int{ 21 | if nums.count == 1 || nums.first! < nums.last! { 22 | return nums[0] 23 | } 24 | if nums.first! == nums.last! { 25 | var min = nums[0] 26 | for num in nums { 27 | if num < min { 28 | min = num 29 | } 30 | } 31 | return min 32 | } 33 | var startIndex = 0 34 | var endIndex = nums.count - 1 35 | while startIndex != endIndex - 1 { 36 | let midIndex = startIndex + (endIndex - startIndex) / 2 37 | if nums[midIndex] >= nums[startIndex] { 38 | startIndex = midIndex 39 | } 40 | if nums[midIndex] <= nums[endIndex] { 41 | endIndex = midIndex 42 | } 43 | } 44 | return nums[endIndex] 45 | } 46 | } 47 | 48 | class UnitTests: XCTestCase { 49 | var solution: Solution! 50 | 51 | override func setUp() { 52 | super.setUp() 53 | solution = Solution() 54 | } 55 | 56 | // 典型输入,单调升序的数组的一个旋转 57 | func testCase1() { 58 | let nums = [3, 4, 5, 1, 2] 59 | XCTAssertEqual(solution.Min(nums), 1) 60 | } 61 | // 有重复数字,并且重复的数字刚好的最小的数字 62 | func testCase2() { 63 | let nums = [3, 4, 5, 1, 1, 2] 64 | XCTAssertEqual(solution.Min(nums), 1) 65 | } 66 | // 有重复数字,但重复的数字不是第一个数字和最后一个数字 67 | func testCase3() { 68 | let nums = [3, 4, 5, 1, 2, 2] 69 | XCTAssertEqual(solution.Min(nums), 1) 70 | } 71 | // 有重复的数字,并且重复的数字刚好是第一个数字和最后一个数字 72 | func testCase4() { 73 | let nums = [1, 0, 1, 1, 1] 74 | XCTAssertEqual(solution.Min(nums), 0) 75 | } 76 | // 单调升序数组,旋转0个元素,也就是单调升序数组本身 77 | func testCase5() { 78 | //let nums = [1, 2, 3, 4, 5] 79 | //XCTAssertEqual(solution.Min(nums), 1) 80 | } 81 | // 数组中只有一个数字 82 | func testCase6() { 83 | let nums = [2] 84 | XCTAssertEqual(solution.Min(nums), 2) 85 | } 86 | } 87 | 88 | UnitTests.defaultTestSuite.run() 89 | -------------------------------------------------------------------------------- /11_MinNumberInRotatedArray.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /12_StringPathInMatrix.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /13_RobotMove.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | //================================================================== 2 | // 《剑指Offer——名企面试官精讲典型编程题》代码 3 | //================================================================== 4 | // 面试题13:机器人的运动范围 5 | // 题目:地上有一个m行n列的方格。一个机器人从坐标(0, 0)的格子开始移动,它 6 | // 每一次可以向左、右、上、下移动一格,但不能进入行坐标和列坐标的数位之和 7 | // 大于k的格子。例如,当k为18时,机器人能够进入方格(35, 37),因为3+5+3+7=18。 8 | // 但它不能进入方格(35, 38),因为3+5+3+8=19。请问该机器人能够到达多少个格子? 9 | 10 | import Foundation 11 | import XCTest 12 | 13 | class Solution { 14 | /** 15 | 计算机器人在m行n列方格中可到达的格子数量 16 | - Parameters: 17 | - rows: 方格行数 18 | - cols: 方格列数 19 | - k: 行坐标和列坐标的数位之和限制 20 | - Returns: 返回能够到达格子数 21 | */ 22 | func Count(rows: Int, cols: Int, k: Int) -> Int{ 23 | var visited = Array(repeating: Array(repeating: false, count: cols), count: rows) 24 | return CountCore(&visited, row: 0, col: 0, k: k) 25 | } 26 | private func CountCore(_ visited: inout [[Bool]], row: Int, col: Int, k: Int) -> Int { 27 | var count = 0 28 | if col >= 0 && row >= 0 && 29 | row < visited.count && col < visited[0].count && 30 | DigitSum(i: row) + DigitSum(i: col) <= k && 31 | !visited[row][col] { 32 | 33 | visited[row][col] = true 34 | count = 1 + CountCore(&visited, row: row - 1, col: col, k: k) + 35 | CountCore(&visited, row: row, col: col - 1, k: k) + 36 | CountCore(&visited, row: row + 1, col: col, k: k) + 37 | CountCore(&visited, row: row, col: col + 1, k: k) 38 | } 39 | return count 40 | } 41 | private func DigitSum(i: Int) -> Int { 42 | var i = i, sum = 0 43 | while i > 0 { 44 | sum += i % 10 45 | i /= 10 46 | } 47 | return sum 48 | } 49 | } 50 | 51 | class UnitTests: XCTestCase { 52 | var solution: Solution! 53 | 54 | override func setUp() { 55 | super.setUp() 56 | solution = Solution() 57 | } 58 | 59 | //10行10列 k为5 60 | func testCase1() { 61 | XCTAssertEqual(solution.Count(rows: 10, cols: 10, k: 5), 21) 62 | } 63 | //20行20列 k为15 64 | func testCase2() { 65 | XCTAssertEqual(solution.Count(rows: 20, cols: 20, k: 15), 359) 66 | } 67 | 68 | //1行100列 k为10 69 | func testCase3() { 70 | XCTAssertEqual(solution.Count(rows: 1, cols: 100, k: 10), 29) 71 | } 72 | //1行10列 k为10 73 | func testCase4() { 74 | XCTAssertEqual(solution.Count(rows: 1, cols: 10, k: 10), 10) 75 | } 76 | 77 | //10行1列 k为15 78 | func testCase5() { 79 | XCTAssertEqual(solution.Count(rows: 100, cols: 1, k: 15), 79) 80 | } 81 | //100行1列 k为15 82 | func testCase6() { 83 | XCTAssertEqual(solution.Count(rows: 10, cols: 1, k: 15), 10) 84 | } 85 | 86 | //1行1列 k为1 87 | func testCase7() { 88 | XCTAssertEqual(solution.Count(rows: 1, cols: 1, k: 15), 1) 89 | } 90 | //1行1列 k为1 91 | func testCase8() { 92 | XCTAssertEqual(solution.Count(rows: 1, cols: 1, k: 0), 1) 93 | } 94 | //10行10列 k为负数 95 | func testCase9() { 96 | XCTAssertEqual(solution.Count(rows: 10, cols: 10, k: -1), 0) 97 | } 98 | } 99 | 100 | UnitTests.defaultTestSuite.run() 101 | -------------------------------------------------------------------------------- /13_RobotMove.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /14_CuttingRope.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | //================================================================== 2 | // 《剑指Offer——名企面试官精讲典型编程题》代码 3 | //================================================================== 4 | // 面试题14:剪绳子 5 | // 题目:给你一根长度为n绳子,请把绳子剪成m段(m、n都是整数,n>1并且m≥1)。 6 | // 每段的绳子的长度记为k[0]、k[1]、……、k[m]。k[0]*k[1]*…*k[m]可能的最大乘 7 | // 积是多少?例如当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此 8 | // 时得到最大的乘积18。 9 | 10 | import Foundation 11 | import XCTest 12 | 13 | class Solution { 14 | /** 15 | 长度为n的绳子剪成m段后的最大乘积(动态规划法) 16 | - Parameters: 17 | - length: 绳子长度 18 | - Returns: 最大乘积 19 | */ 20 | func maxProductAfterCutting_solution1(length: Int) -> Int { 21 | if length < 2 { 22 | //length = 1时只能剪成 1和0 1*0 23 | return 0 24 | } 25 | if length == 2 { 26 | //1*1 27 | return 1 28 | } 29 | if length == 3 { 30 | //1*2 31 | return 2 32 | } 33 | //maxProduct[n] 为把长度为n的绳子剪成若干段后各段长度乘积的最大值 34 | var products = [0, 1, 2, 3] 35 | var max = 0 36 | for i in 4...length { 37 | max = 0 38 | for j in 1...i/2 { 39 | let product = products[j] * products[i-j] 40 | if product > max { 41 | max = product 42 | } 43 | } 44 | products.append(max) 45 | } 46 | return products[length] 47 | } 48 | /** 49 | 贪心算法:尽可能多地减去长度为3的绳子段,当绳子最后剩下的长度为4的时候,剪成2*2的2段 50 | - Parameters: 51 | - length: 绳子长度 52 | - Returns: 段数的最大乘积 53 | */ 54 | func maxProductAfterCutting_solution2(length: Int) -> Int { 55 | if length < 2 { 56 | return 0 57 | } 58 | if length == 2 { 59 | return 1 60 | } 61 | if length == 3 { 62 | return 2 63 | } 64 | if length % 3 == 1 { 65 | return Int(truncating: (pow(3, length / 3 - 1) * 4) as NSDecimalNumber) 66 | } 67 | else if length % 3 == 0 { 68 | return Int(truncating: (pow(3, length / 3)) as NSDecimalNumber) 69 | } 70 | else { 71 | return Int(truncating: (pow(3, length / 3) * 2) as NSDecimalNumber) 72 | } 73 | } 74 | } 75 | 76 | 77 | class UnitTests: XCTestCase { 78 | var solution: Solution! 79 | 80 | override func setUp() { 81 | super.setUp() 82 | solution = Solution() 83 | } 84 | //长度为1 85 | func testCase1() { 86 | XCTAssertEqual(solution.maxProductAfterCutting_solution1(length: 1), 0) 87 | XCTAssertEqual(solution.maxProductAfterCutting_solution2(length: 1), 0) 88 | } 89 | //长度为2 90 | func testCase2() { 91 | XCTAssertEqual(solution.maxProductAfterCutting_solution1(length: 2), 1) 92 | XCTAssertEqual(solution.maxProductAfterCutting_solution2(length: 2), 1) 93 | } 94 | //长度为3 95 | func testCase3() { 96 | XCTAssertEqual(solution.maxProductAfterCutting_solution1(length: 3), 2) 97 | XCTAssertEqual(solution.maxProductAfterCutting_solution2(length: 3), 2) 98 | } 99 | //长度为4 100 | func testCase4() { 101 | XCTAssertEqual(solution.maxProductAfterCutting_solution1(length: 4), 4) 102 | XCTAssertEqual(solution.maxProductAfterCutting_solution2(length: 4), 4) 103 | } 104 | //长度为5 105 | func testCase5() { 106 | XCTAssertEqual(solution.maxProductAfterCutting_solution1(length: 5), 6) 107 | XCTAssertEqual(solution.maxProductAfterCutting_solution2(length: 5), 6) 108 | } 109 | //长度为6 110 | func testCase6() { 111 | XCTAssertEqual(solution.maxProductAfterCutting_solution1(length: 6), 9) 112 | XCTAssertEqual(solution.maxProductAfterCutting_solution2(length: 6), 9) 113 | } 114 | //长度为7 115 | func testCase7() { 116 | XCTAssertEqual(solution.maxProductAfterCutting_solution1(length: 7), 12) 117 | XCTAssertEqual(solution.maxProductAfterCutting_solution2(length: 7), 12) 118 | } 119 | //长度为8 120 | func testCase8() { 121 | XCTAssertEqual(solution.maxProductAfterCutting_solution1(length: 8), 18) 122 | XCTAssertEqual(solution.maxProductAfterCutting_solution2(length: 8), 18) 123 | } 124 | //长度为9 125 | func testCase9() { 126 | XCTAssertEqual(solution.maxProductAfterCutting_solution1(length: 9), 27) 127 | XCTAssertEqual(solution.maxProductAfterCutting_solution2(length: 9), 27) 128 | } 129 | //长度为10 130 | func testCase10() { 131 | XCTAssertEqual(solution.maxProductAfterCutting_solution1(length: 10), 36) 132 | XCTAssertEqual(solution.maxProductAfterCutting_solution2(length: 10), 36) 133 | } 134 | //长度为50 135 | func testCase11() { 136 | XCTAssertEqual(solution.maxProductAfterCutting_solution1(length: 50), 86093442) 137 | XCTAssertEqual(solution.maxProductAfterCutting_solution2(length: 50), 86093442) 138 | } 139 | } 140 | 141 | UnitTests.defaultTestSuite.run() 142 | -------------------------------------------------------------------------------- /14_CuttingRope.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /15_NumberOf1InBinary.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | //================================================================== 2 | // 《剑指Offer——名企面试官精讲典型编程题》代码 3 | //================================================================== 4 | // 面试题15:二进制中1的个数 5 | // 题目:请实现一个函数,输入一个整数,输出该数二进制表示中1的个数。例如 6 | // 把9表示成二进制是1001,有2位是1。因此如果输入9,该函数输出2。 7 | 8 | import Foundation 9 | import XCTest 10 | 11 | class Solution { 12 | /** 13 | 方法:将输入的整数与flag(初始值为1)进行按位与运算,如果大于0,则计数+1 14 | 每次比较完将flag左移1位再比较,直到flag=0 15 | - Parameters: 16 | - num: 输入的整数 17 | - Returns: i的2进制表示中1的个数 18 | */ 19 | func NumberOf1_Solution1(_ num: Int) -> Int { 20 | var count = 0 21 | var flag = 1 22 | while flag != 0 { 23 | if flag & num > 0 { 24 | count += 1 25 | } 26 | flag = flag << 1 27 | } 28 | return count 29 | } 30 | /** 31 | 方法:将整数 num-1 与 num 做与运算,会把该整数的最右边的1变成0 32 | 那么1个整数二进制有多少个1就可以进行多少次这样操作 33 | - Parameters: 34 | - num: 输入的整数 35 | - Returns: i的2进制表示中1的个数 36 | */ 37 | func NumberOf1_Solution2(_ num: Int) -> Int { 38 | var count = 0 39 | var num = num 40 | while num > 0 { 41 | count += 1 42 | num = num & (num - 1) 43 | } 44 | return count 45 | } 46 | } 47 | 48 | 49 | class UnitTests: XCTestCase { 50 | var solution: Solution! 51 | 52 | override func setUp() { 53 | super.setUp() 54 | solution = Solution() 55 | } 56 | //输入0 57 | func testCase1() { 58 | XCTAssertEqual(solution.NumberOf1_Solution1(0), 0) 59 | XCTAssertEqual(solution.NumberOf1_Solution2(0), 0) 60 | } 61 | //输入1 62 | func testCase2() { 63 | XCTAssertEqual(solution.NumberOf1_Solution1(1), 1) 64 | XCTAssertEqual(solution.NumberOf1_Solution2(1), 1) 65 | } 66 | //输入10 67 | func testCase3() { 68 | XCTAssertEqual(solution.NumberOf1_Solution1(10), 2) 69 | XCTAssertEqual(solution.NumberOf1_Solution2(10), 2) 70 | } 71 | //输入0x7FFFFFFF 72 | func testCase4() { 73 | XCTAssertEqual(solution.NumberOf1_Solution1(Int("7FFFFFFF", radix: 16)!), 31) 74 | XCTAssertEqual(solution.NumberOf1_Solution2(Int("7FFFFFFF", radix: 16)!), 31) 75 | } 76 | 77 | //输入0xFFFFFFFF 负数 78 | func testCase5() { 79 | XCTAssertEqual(solution.NumberOf1_Solution1(Int("FFFFFFFF", radix: 16)!), 32) 80 | XCTAssertEqual(solution.NumberOf1_Solution2(Int("FFFFFFFF", radix: 16)!), 32) 81 | } 82 | 83 | //输入0x80000000(负数),期待的输出是1 84 | func testCase6() { 85 | XCTAssertEqual(solution.NumberOf1_Solution1(Int("80000000", radix: 16)!), 1) 86 | XCTAssertEqual(solution.NumberOf1_Solution2(Int("80000000", radix: 16)!), 1) 87 | } 88 | } 89 | 90 | UnitTests.defaultTestSuite.run() 91 | -------------------------------------------------------------------------------- /15_NumberOf1InBinary.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /16_Power.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | //================================================================== 2 | // 《剑指Offer——名企面试官精讲典型编程题》代码 3 | //================================================================== 4 | // 面试题16:数值的整数次方 5 | // 题目:实现函数double Power(double base, int exponent),求base的exponent 6 | // 次方。不得使用库函数,同时不需要考虑大数问题。 7 | // 主要考察代码规范性、完整性 8 | // 需要考虑exponent为0、负数的情况以及错误处理 9 | 10 | import Foundation 11 | import XCTest 12 | 13 | class Solution { 14 | /** 15 | 计算base的exponent次幂,exponent为正数 16 | - Parameters: 17 | - base:底数 18 | - exponent: 指数 19 | - Returns: 如果无法求值,返回nil,否者返回幂指数的结果 20 | */ 21 | func pow(_ base: Double, exponent: Int) -> Double? { 22 | if base == 0 && exponent < 0 { 23 | return nil 24 | } 25 | let absExp = exponent < 0 ? -exponent : exponent 26 | var result = powExp(base, exponent: absExp) 27 | if exponent < 0 { 28 | result = 1 / result 29 | } 30 | return result 31 | } 32 | /** 33 | 计算base的exponent次幂,exponent为正数 34 | - Parameters: 35 | - base:底数 36 | - exponent: 指数 37 | - Returns: 幂指数的结果 38 | */ 39 | private func powExp(_ base: Double, exponent: Int) -> Double { 40 | if exponent == 0 { 41 | return 1 42 | } 43 | if exponent == 1 { 44 | return base 45 | } 46 | var result = powExp(base, exponent: exponent / 2) 47 | result *= result 48 | if exponent % 2 == 1 { 49 | result *= base 50 | } 51 | return result 52 | } 53 | } 54 | 55 | class UnitTests: XCTestCase { 56 | var solution: Solution! 57 | 58 | override func setUp() { 59 | super.setUp() 60 | solution = Solution() 61 | } 62 | //底数2,指数3,结果8 63 | func testCase1() { 64 | XCTAssertEqual(solution.pow(2, exponent: 3), 8) 65 | } 66 | //底数-2,指数3,结果-8 67 | func testCase2() { 68 | XCTAssertEqual(solution.pow(-2, exponent: 3), -8) 69 | } 70 | //底数2,指数-3,结果0.125 71 | func testCase3() { 72 | XCTAssertEqual(solution.pow(2, exponent: -3), 1/8) 73 | } 74 | //底数2,指数0,结果1 75 | func testCase4() { 76 | XCTAssertEqual(solution.pow(2, exponent: 0), 1) 77 | } 78 | //底数0,指数0,结果1 79 | func testCase5() { 80 | XCTAssertEqual(solution.pow(0, exponent: 0), 1) 81 | } 82 | //底数0,指数4,结果0 83 | func testCase6() { 84 | XCTAssertEqual(solution.pow(0, exponent: 4), 0) 85 | } 86 | //底数0,指数-4,结果nil 87 | func testCase7() { 88 | XCTAssertEqual(solution.pow(0, exponent: -4), nil) 89 | } 90 | } 91 | 92 | UnitTests.defaultTestSuite.run() 93 | -------------------------------------------------------------------------------- /16_Power.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /17_Print1ToMaxOfNDigits.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | //================================================================== 2 | // 《剑指Offer——名企面试官精讲典型编程题》代码 3 | //================================================================== 4 | // 面试题17:打印1到最大的n位数 5 | // 题目:输入数字n,按顺序打印出从1最大的n位十进制数。比如输入3,则 6 | // 打印出1、2、3一直到最大的3位数即999。 7 | 8 | import Foundation 9 | import XCTest 10 | 11 | class Solution { 12 | 13 | private let digitsDict:[Character] = ["0","1","2","3","4","5","6","7","8","9"] 14 | 15 | /** 16 | 按顺序打印出从1最大的n位十进制数 17 | 主要考察n比较大时,long longlong都不能表示的情况 18 | - Parameters: 19 | - n:最大的位数 20 | */ 21 | func print1ToMaxOfNDigits(_ n: Int){ 22 | if n <= 0 { 23 | return 24 | } 25 | var charArray: [Character] = Array(repeating: "0", count: n) 26 | for i in 0.. 2 | 3 | 4 | -------------------------------------------------------------------------------- /18_01_DeleteNodeInList.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | //================================================================== 2 | // 《剑指Offer——名企面试官精讲典型编程题》代码 3 | //================================================================== 4 | // 面试题18(一):在O(1)时间删除链表结点 5 | // 题目:给定单向链表的头指针和一个结点指针,定义一个函数在O(1)时间删除该 6 | // 结点。 7 | 8 | import Foundation 9 | import XCTest 10 | 11 | //链表节点 12 | class ListNode { 13 | var next: ListNode? 14 | var value: Int 15 | 16 | init(value: Int, next: ListNode?) { 17 | self.value = value 18 | self.next = next 19 | } 20 | } 21 | 22 | 23 | class Solution { 24 | /** 25 | o(1)方式删除链表的给定节点 26 | - Parameters: 27 | - head:头节点 28 | - toBeDeleted: 需要删除的节点 29 | */ 30 | func deleteNode(_ head: inout ListNode?, _ toBeDeleted: ListNode?){ 31 | if head == nil || toBeDeleted == nil { 32 | return 33 | } 34 | //链表只有1个节点,也就是删除head本身 35 | if head! === toBeDeleted! { 36 | head = nil 37 | return 38 | } 39 | //需要删除的节点位于尾部,需要从head开始便利到node前面的节点 40 | if toBeDeleted!.next === nil { 41 | var node = head! 42 | while node.next! !== toBeDeleted! { 43 | node = node.next! 44 | } 45 | node.next = nil //删除 46 | }else { 47 | //不位于尾部,只需要toBeDeleted之后的节点ANode内容复制到toBeDeleted 48 | //然后删除ANode即可 49 | var node = toBeDeleted!.next 50 | toBeDeleted!.next = node!.next 51 | toBeDeleted!.value = node!.value 52 | node = nil 53 | } 54 | } 55 | } 56 | 57 | class UnitTests: XCTestCase { 58 | var solution: Solution! 59 | 60 | override func setUp() { 61 | super.setUp() 62 | solution = Solution() 63 | } 64 | 65 | //1->2->3->4->5 删除3 66 | func testCase1() { 67 | let node5:ListNode? = ListNode(value: 5, next: nil) 68 | let node4:ListNode? = ListNode(value: 4, next: node5) 69 | let node3:ListNode? = ListNode(value: 3, next: node4) 70 | let node2:ListNode? = ListNode(value: 2, next: node3) 71 | var node1:ListNode? = ListNode(value: 1, next: node2) 72 | solution.deleteNode(&node1, node3) 73 | XCTAssertEqual(node1!.value, 1) 74 | XCTAssertEqual(node1!.next?.value, 2) 75 | XCTAssertEqual(node1!.next?.next?.value,4) 76 | XCTAssertEqual(node1!.next?.next?.next?.value,5) 77 | } 78 | //1->2->3->4->5 删除5 79 | func testCase2() { 80 | let node5:ListNode? = ListNode(value: 5, next: nil) 81 | let node4:ListNode? = ListNode(value: 4, next: node5) 82 | let node3:ListNode? = ListNode(value: 3, next: node4) 83 | let node2:ListNode? = ListNode(value: 2, next: node3) 84 | var node1:ListNode? = ListNode(value: 1, next: node2) 85 | solution.deleteNode(&node1, node5) 86 | XCTAssertEqual(node1!.value, 1) 87 | XCTAssertEqual(node1!.next?.value, 2) 88 | XCTAssertEqual(node1!.next?.next?.value,3) 89 | XCTAssertEqual(node1!.next?.next?.next?.value,4) 90 | XCTAssertNil(node1!.next!.next!.next!.next) 91 | } 92 | 93 | //1->2->3->4->5 删除1 94 | func testCase3() { 95 | let node5:ListNode? = ListNode(value: 5, next: nil) 96 | let node4:ListNode? = ListNode(value: 4, next: node5) 97 | let node3:ListNode? = ListNode(value: 3, next: node4) 98 | let node2:ListNode? = ListNode(value: 2, next: node3) 99 | var node1:ListNode? = ListNode(value: 1, next: node2) 100 | solution.deleteNode(&node1, node1) 101 | XCTAssertNil(node1) 102 | } 103 | 104 | //只有1个节点1 删除1 105 | func testCase4() { 106 | var node1:ListNode? = ListNode(value: 1, next: nil) 107 | solution.deleteNode(&node1, node1) 108 | XCTAssertNil(node1) 109 | } 110 | } 111 | 112 | UnitTests.defaultTestSuite.run() 113 | -------------------------------------------------------------------------------- /18_01_DeleteNodeInList.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /18_02_DeleteDuplicatedNode.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /19_RegularExpressionsMatching.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | //================================================================== 2 | // 《剑指Offer——名企面试官精讲典型编程题》代码 3 | //================================================================== 4 | // 面试题19:正则表达式匹配 5 | // 题目:请实现一个函数用来匹配包含'.'和'*'的正则表达式。模式中的字符'.' 6 | // 表示任意一个字符,而'*'表示它前面的字符可以出现任意次(含0次)。在本题 7 | // 中,匹配是指字符串的所有字符匹配整个模式。例如,字符串"aaa"与模式"a.a" 8 | // 和"ab*ac*a"匹配,但与"aa.a"及"ab*a"均不匹配。 9 | 10 | import Foundation 11 | import XCTest 12 | 13 | class Solution { 14 | /** 15 | 判断字符串str是否匹配模式pattern 16 | - Parameters: 17 | - str: 待匹配的字符串s 18 | - pattern: 模式 19 | - Returns: 是否匹配 20 | */ 21 | func match(str: String, pattern: String) -> Bool { 22 | return matchCore(str: Array(str), strIndex: 0, pattern: Array(pattern), patternIndex: 0) 23 | } 24 | /** 25 | 匹配核心函数 26 | - Parameters: 27 | - str: 待匹配的字符串数组 28 | - strIndex: str数组当前索引 29 | - pattern: 模式数组 30 | - patternIndex: 模式数组当前索引 31 | - Returns: 是否匹配 32 | */ 33 | private func matchCore(str: [Character], strIndex: Int, pattern: [Character], patternIndex: Int) -> Bool { 34 | if !inRange(str, strIndex) && !inRange(pattern, patternIndex) { 35 | return true 36 | } 37 | if inRange(str, strIndex) && !inRange(pattern, patternIndex) { 38 | return false 39 | } 40 | 41 | if inRange(pattern, patternIndex + 1) && pattern[patternIndex + 1] == "*" { 42 | if inRange(str, strIndex) && 43 | (pattern[patternIndex] == "." || pattern[patternIndex] == str[strIndex]) { 44 | return matchCore(str:str, strIndex: strIndex + 1, pattern: pattern, patternIndex: patternIndex + 2) || matchCore(str:str, strIndex: strIndex + 1, pattern: pattern, patternIndex: patternIndex) || matchCore(str:str, strIndex: strIndex, pattern: pattern, patternIndex: patternIndex + 2) 45 | } else { 46 | return matchCore(str:str, strIndex: strIndex, pattern: pattern, patternIndex: patternIndex + 2) 47 | } 48 | } 49 | 50 | if(inRange(str, strIndex) && inRange(pattern, patternIndex)) && 51 | (str[strIndex] == pattern[patternIndex] || (pattern[patternIndex] == ".")) { 52 | return matchCore(str:str, strIndex: strIndex + 1, pattern: pattern, patternIndex: patternIndex + 1) 53 | } 54 | return false 55 | } 56 | /** 57 | 判断index是否是arr的合理索引 58 | - Parameters: 59 | - arr: 数组 60 | - index: 索引 61 | - Returns: 是否匹配 62 | */ 63 | private func inRange(_ arr: [T], _ index: Int) -> Bool { 64 | if index < arr.count && index >= 0 { 65 | return true 66 | } 67 | return false 68 | } 69 | } 70 | 71 | class UnitTests: XCTestCase { 72 | var solution: Solution! 73 | 74 | override func setUp() { 75 | super.setUp() 76 | solution = Solution() 77 | } 78 | func testCase1(){ 79 | XCTAssertTrue(solution.match(str: "", pattern: "")) 80 | XCTAssertTrue(solution.match(str: "", pattern: ".*")) 81 | XCTAssertFalse(solution.match(str: "", pattern: ".")) 82 | XCTAssertTrue(solution.match(str: "", pattern: "c*")) 83 | XCTAssertTrue(solution.match(str: "a", pattern: ".*")) 84 | XCTAssertFalse(solution.match(str: "a", pattern: "a.")) 85 | XCTAssertFalse(solution.match(str: "a", pattern: "")) 86 | XCTAssertTrue(solution.match(str: "a", pattern: ".")) 87 | XCTAssertTrue(solution.match(str: "a", pattern: "ab*")) 88 | XCTAssertFalse(solution.match(str: "a", pattern: "ab*a")) 89 | XCTAssertTrue(solution.match(str: "aa", pattern: "aa")) 90 | XCTAssertTrue(solution.match(str: "aa", pattern: "a*")) 91 | XCTAssertTrue(solution.match(str: "aa", pattern: ".*")) 92 | XCTAssertFalse(solution.match(str: "aa", pattern: ".")) 93 | XCTAssertTrue(solution.match(str: "ab", pattern: ".*")) 94 | XCTAssertTrue(solution.match(str: "aaa", pattern: "aa*")) 95 | XCTAssertFalse(solution.match(str: "aaa", pattern: "aa.a")) 96 | XCTAssertTrue(solution.match(str: "aaa", pattern: "a.a")) 97 | XCTAssertFalse(solution.match(str: "aaa", pattern: ".a")) 98 | XCTAssertTrue(solution.match(str: "aaa", pattern: "a*a")) 99 | XCTAssertFalse(solution.match(str: "aaa", pattern: "ab*a")) 100 | XCTAssertTrue(solution.match(str: "aaa", pattern: "ab*ac*a")) 101 | XCTAssertTrue(solution.match(str: "aaa", pattern: "ab*a*c*a")) 102 | XCTAssertTrue(solution.match(str: "aaa", pattern: ".*")) 103 | XCTAssertTrue(solution.match(str: "aab", pattern: "c*a*b")) 104 | XCTAssertTrue(solution.match(str: "aaca", pattern: "ab*a*c*a")) 105 | XCTAssertFalse(solution.match(str: "aaba", pattern: "ab*a*c*a")) 106 | XCTAssertTrue(solution.match(str: "bbbba", pattern: ".*a*a")) 107 | XCTAssertFalse(solution.match(str: "bcbbabab", pattern: ".*a*a")) 108 | } 109 | } 110 | 111 | UnitTests.defaultTestSuite.run() 112 | -------------------------------------------------------------------------------- /19_RegularExpressionsMatching.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /20_NumericStrings.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | //================================================================== 2 | // 《剑指Offer——名企面试官精讲典型编程题》代码 3 | //================================================================== 4 | // 面试题20:表示数值的字符串 5 | // 题目:请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。例如, 6 | // 字符串“+100”、“5e2”、“-123”、“3.1416”及“-1E-16”都表示数值,但“12e”、 7 | // “1a3.14”、“1.2.3”、“+-5”及“12e+5.4”都不是 8 | 9 | import Foundation 10 | import XCTest 11 | 12 | class Solution { 13 | 14 | private let digits: [Character] = ["0","1","2","3","4","5","6","7","8","9"] 15 | 16 | /** 17 | 数字的格式可以用A[.[B]][e|EC]或者.B[e|EC]表示,其中A和C都是 18 | 整数(可以有正负号,也可以没有),而B是一个无符号整数 19 | - Parameters: 20 | - str: 字符串 21 | - Returns: 字符串是否可以表示数值 22 | */ 23 | func isNumeric(str: String) -> Bool { 24 | if str == "" { 25 | return false 26 | } 27 | let str = Array(str) 28 | //查找正负号以及整数部分 29 | var (numeric, index) = scanInteger(str: str, startIndex: 0) 30 | 31 | //如果之后是小数点 32 | if index < str.count && str[index] == "." { 33 | index += 1 34 | //查找小数点之后的数字部分 35 | let result = scanUnsignedInteger(str: str, startIndex: index) 36 | numeric = numeric || result.0 37 | index = result.1 38 | } 39 | //如果之后是e或者E 40 | if index < str.count - 1 && (str[index] == "e" || str[index] == "E") { 41 | index += 1 42 | let result = scanInteger(str: str, startIndex: index) 43 | numeric = numeric && result.0 44 | index = result.1 45 | } 46 | return numeric && (index == str.count) 47 | } 48 | /** 49 | 匹配数值字符串中整数部分(可能包含+和-符号) 50 | - Parameters: 51 | - str: 字符串 52 | - startIndex: 当前匹配索引 53 | - Returns:(是否有整数部分, 整数结束索引) 54 | */ 55 | private func scanInteger(str: [Character], startIndex: Int) -> (Bool, Int) { 56 | var startIndex = startIndex 57 | if str[startIndex] == "+" || str[startIndex] == "-" { 58 | startIndex += 1 59 | } 60 | return scanUnsignedInteger(str: str, startIndex: startIndex) 61 | } 62 | /** 63 | 匹配数值字符串中无符号整数部分, A[.[B]][e|EC] 即:其中的A(移除正负符号后)和B 64 | - Parameters: 65 | - str: 字符串 66 | - startIndex: 当前匹配索引 67 | - Returns: (是否有整数部分, 整数结束索引) 68 | */ 69 | private func scanUnsignedInteger(str: [Character], startIndex: Int) -> (Bool, Int) { 70 | var i = startIndex 71 | while i < str.count && digits.contains(str[i]) { 72 | i += 1 73 | } 74 | return (i > startIndex, i) 75 | } 76 | } 77 | 78 | class UnitTests: XCTestCase { 79 | var solution: Solution! 80 | 81 | override func setUp() { 82 | super.setUp() 83 | solution = Solution() 84 | } 85 | func testCase1(){ 86 | XCTAssertEqual(solution.isNumeric(str: "100"), true) 87 | XCTAssertEqual(solution.isNumeric(str: "123.45e+6"), true) 88 | XCTAssertEqual(solution.isNumeric(str: "+500"), true) 89 | XCTAssertEqual(solution.isNumeric(str: "5e2"), true) 90 | XCTAssertEqual(solution.isNumeric(str: "3.1416"), true) 91 | XCTAssertEqual(solution.isNumeric(str: "600."), true) 92 | XCTAssertEqual(solution.isNumeric(str: "-.123"), true) 93 | XCTAssertEqual(solution.isNumeric(str: "-1E-16"), true) 94 | XCTAssertEqual(solution.isNumeric(str: "1.79769313486232E+308"), true) 95 | XCTAssertEqual(solution.isNumeric(str: "12e"), false) 96 | XCTAssertEqual(solution.isNumeric(str: "1a3.14"), false) 97 | XCTAssertEqual(solution.isNumeric(str: "1+23"), false) 98 | XCTAssertEqual(solution.isNumeric(str: "1.2.3"), false) 99 | XCTAssertEqual(solution.isNumeric(str: "+-5"), false) 100 | XCTAssertEqual(solution.isNumeric(str: "12e+5.4"), false) 101 | XCTAssertEqual(solution.isNumeric(str: "."), false) 102 | XCTAssertEqual(solution.isNumeric(str: ".e1"), false) 103 | XCTAssertEqual(solution.isNumeric(str: "+."), false) 104 | XCTAssertEqual(solution.isNumeric(str: ""), false) 105 | } 106 | } 107 | 108 | UnitTests.defaultTestSuite.run() 109 | -------------------------------------------------------------------------------- /20_NumericStrings.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /21_ReorderArray.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | //================================================================== 2 | // 《剑指Offer——名企面试官精讲典型编程题》代码 3 | //================================================================== 4 | // 面试题21:调整数组顺序使奇数位于偶数前面 5 | // 题目:输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有 6 | // 奇数位于数组的前半部分,所有偶数位于数组的后半部分。 7 | 8 | 9 | import Foundation 10 | import XCTest 11 | 12 | class Solution { 13 | /** 14 | 调整数组,将数组中的所有奇数位于偶数之前 15 | - Parameters: 16 | - array: 待排序的数组 17 | - Returns: 排序后的数组 18 | */ 19 | func ReorderOddEven(array: [Int]) -> [Int] { 20 | return reorder(array: array, criteria: { ($0 % 2) == 0 ? false : true}) 21 | } 22 | /** 23 | 从数组的头尾向中间遍历数组并调整(criteria) 24 | - Parameters: 25 | - array: 待调整的数组 26 | - criteria: 调整方法 27 | - Returns: 调整后的数组 28 | */ 29 | private func reorder(array: [Int], criteria: (Int) -> Bool) -> [Int] { 30 | var array = array 31 | var startIndex = 0 32 | var endIndex = array.count - 1 33 | while startIndex < endIndex { 34 | while startIndex < endIndex && criteria(array[startIndex]) { 35 | startIndex += 1 36 | } 37 | while startIndex < endIndex && !criteria(array[endIndex]) { 38 | endIndex -= 1 39 | } 40 | if startIndex < endIndex { 41 | let temp = array[startIndex] 42 | array[startIndex] = array[endIndex] 43 | array[endIndex] = temp 44 | } 45 | } 46 | return array 47 | } 48 | 49 | } 50 | 51 | class UnitTests: XCTestCase { 52 | var solution: Solution! 53 | 54 | override func setUp() { 55 | super.setUp() 56 | solution = Solution() 57 | } 58 | func testCase1(){ 59 | let result = solution.ReorderOddEven(array: [1,2,3,4,5,6,7]) 60 | XCTAssertEqual(result[0], 1) 61 | XCTAssertEqual(result[1], 7) 62 | XCTAssertEqual(result[2], 3) 63 | XCTAssertEqual(result[3], 5) 64 | XCTAssertEqual(result[4], 4) 65 | XCTAssertEqual(result[5], 6) 66 | XCTAssertEqual(result[6], 2) 67 | } 68 | func testCase2(){ 69 | let result = solution.ReorderOddEven(array: [2,4,6,1,3,5,7]) 70 | XCTAssertEqual(result[0], 7) 71 | XCTAssertEqual(result[1], 5) 72 | XCTAssertEqual(result[2], 3) 73 | XCTAssertEqual(result[3], 1) 74 | XCTAssertEqual(result[4], 6) 75 | XCTAssertEqual(result[5], 4) 76 | XCTAssertEqual(result[6], 2) 77 | } 78 | func testCase3(){ 79 | let result = solution.ReorderOddEven(array: [1,3,5,7,2,4,6]) 80 | XCTAssertEqual(result[0], 1) 81 | XCTAssertEqual(result[1], 3) 82 | XCTAssertEqual(result[2], 5) 83 | XCTAssertEqual(result[3], 7) 84 | XCTAssertEqual(result[4], 2) 85 | XCTAssertEqual(result[5], 4) 86 | XCTAssertEqual(result[6], 6) 87 | } 88 | func testCase4(){ 89 | let result = solution.ReorderOddEven(array: [1]) 90 | XCTAssertEqual(result[0], 1) 91 | } 92 | func testCase5(){ 93 | let result = solution.ReorderOddEven(array: [2]) 94 | XCTAssertEqual(result[0], 2) 95 | } 96 | 97 | } 98 | 99 | UnitTests.defaultTestSuite.run() 100 | -------------------------------------------------------------------------------- /21_ReorderArray.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /22_KthNodeFromEnd.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | //================================================================== 2 | // 《剑指Offer——名企面试官精讲典型编程题》代码 3 | //================================================================== 4 | // 面试题22:链表中倒数第k个结点 5 | // 题目:输入一个链表,输出该链表中倒数第k个结点。为了符合大多数人的习惯, 6 | // 本题从1开始计数,即链表的尾结点是倒数第1个结点。例如一个链表有6个结点, 7 | // 从头结点开始它们的值依次是1、2、3、4、5、6。这个链表的倒数第3个结点是 8 | // 值为4的结点。 9 | 10 | import Foundation 11 | import XCTest 12 | 13 | //定义链表节点 14 | class ListNode { 15 | var next: ListNode? 16 | var value: Int 17 | 18 | init(value: Int, next: ListNode?) { 19 | self.value = value 20 | self.next = next 21 | } 22 | } 23 | 24 | class Solution { 25 | /** 26 | 查找链表中的倒数第K个节点 27 | - Parameters: 28 | - head: 链表的头节点 29 | - Returns: 倒数第k个节点(从1开始计数,最后一个即为倒数第1个) 30 | */ 31 | func FindKthToTail(_ head: ListNode?, k: Int) -> ListNode? { 32 | if head == nil || k <= 0 { 33 | return nil 34 | } 35 | var pNode1: ListNode? = head 36 | var pNode2: ListNode = head! 37 | for _ in 0..2->3->4->5 倒数第2个节点值是4 60 | func testCase1(){ 61 | let node1:ListNode = ListNode(value: 1, next: nil) 62 | let node2:ListNode = ListNode(value: 2, next: nil) 63 | let node3:ListNode = ListNode(value: 3, next: nil) 64 | let node4:ListNode = ListNode(value: 4, next: nil) 65 | let node5:ListNode = ListNode(value: 5, next: nil) 66 | node1.next = node2 67 | node2.next = node3 68 | node3.next = node4 69 | node4.next = node5 70 | XCTAssertEqual(solution.FindKthToTail(node1, k: 2)?.value, 4) 71 | } 72 | //1->2->3->4->5 倒数第1个节点值是5 73 | func testCase2(){ 74 | let node1:ListNode = ListNode(value: 1, next: nil) 75 | let node2:ListNode = ListNode(value: 2, next: nil) 76 | let node3:ListNode = ListNode(value: 3, next: nil) 77 | let node4:ListNode = ListNode(value: 4, next: nil) 78 | let node5:ListNode = ListNode(value: 5, next: nil) 79 | node1.next = node2 80 | node2.next = node3 81 | node3.next = node4 82 | node4.next = node5 83 | XCTAssertEqual(solution.FindKthToTail(node1, k: 1)?.value, 5) 84 | } 85 | //1->2->3->4->5 倒数第5个节点值是1 86 | func testCase3(){ 87 | let node1:ListNode = ListNode(value: 1, next: nil) 88 | let node2:ListNode = ListNode(value: 2, next: nil) 89 | let node3:ListNode = ListNode(value: 3, next: nil) 90 | let node4:ListNode = ListNode(value: 4, next: nil) 91 | let node5:ListNode = ListNode(value: 5, next: nil) 92 | node1.next = node2 93 | node2.next = node3 94 | node3.next = node4 95 | node4.next = node5 96 | XCTAssertEqual(solution.FindKthToTail(node1, k: 5)?.value, 1) 97 | } 98 | //测试空链表 99 | func testCase4(){ 100 | XCTAssertNil(solution.FindKthToTail(nil, k: 5)) 101 | } 102 | //1->2->3->4->5 k大于节点数 103 | func testCase5(){ 104 | let node1:ListNode = ListNode(value: 1, next: nil) 105 | let node2:ListNode = ListNode(value: 2, next: nil) 106 | let node3:ListNode = ListNode(value: 3, next: nil) 107 | let node4:ListNode = ListNode(value: 4, next: nil) 108 | let node5:ListNode = ListNode(value: 5, next: nil) 109 | node1.next = node2 110 | node2.next = node3 111 | node3.next = node4 112 | node4.next = node5 113 | XCTAssertNil(solution.FindKthToTail(node1, k: 6)) 114 | } 115 | //1->2->3->4->5 k=0 116 | func testCase6(){ 117 | let node1:ListNode = ListNode(value: 1, next: nil) 118 | let node2:ListNode = ListNode(value: 2, next: nil) 119 | let node3:ListNode = ListNode(value: 3, next: nil) 120 | let node4:ListNode = ListNode(value: 4, next: nil) 121 | let node5:ListNode = ListNode(value: 5, next: nil) 122 | node1.next = node2 123 | node2.next = node3 124 | node3.next = node4 125 | node4.next = node5 126 | XCTAssertNil(solution.FindKthToTail(node1, k: 0)) 127 | } 128 | 129 | } 130 | 131 | UnitTests.defaultTestSuite.run() 132 | -------------------------------------------------------------------------------- /22_KthNodeFromEnd.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /23_EntryNodeInListLoop.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /24_ReverseList.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | //================================================================== 2 | // 《剑指Offer——名企面试官精讲典型编程题》代码 3 | //================================================================== 4 | // 面试题24:反转链表 5 | // 题目:定义一个函数,输入一个链表的头结点,反转该链表并输出反转后链表的 6 | // 头结点。 7 | 8 | import Foundation 9 | import XCTest 10 | 11 | //定义链表节点 12 | class ListNode { 13 | var next: ListNode? 14 | var value: Int 15 | 16 | init(value: Int, next: ListNode?) { 17 | self.value = value 18 | self.next = next 19 | } 20 | } 21 | 22 | class Solution { 23 | /** 24 | 反转链表 25 | - Parameters: 26 | - head: 链表的头节点 27 | - Returns: 返回旋转之后的链表 28 | */ 29 | func ReverseList(_ head: ListNode?) -> ListNode? { 30 | var reversedHead: ListNode? = nil 31 | var node: ListNode? = head 32 | var prev: ListNode? = nil 33 | while node != nil { 34 | let next = node?.next 35 | if next == nil { 36 | reversedHead = node 37 | } 38 | node?.next = prev 39 | prev = node 40 | node = next 41 | } 42 | return reversedHead 43 | } 44 | } 45 | 46 | class UnitTests: XCTestCase { 47 | var solution: Solution! 48 | 49 | override func setUp() { 50 | super.setUp() 51 | solution = Solution() 52 | } 53 | //多个节点 54 | func testCase1(){ 55 | let node1:ListNode = ListNode(value: 1, next: nil) 56 | let node2:ListNode = ListNode(value: 2, next: nil) 57 | let node3:ListNode = ListNode(value: 3, next: nil) 58 | let node4:ListNode = ListNode(value: 4, next: nil) 59 | let node5:ListNode = ListNode(value: 5, next: nil) 60 | node1.next = node2 61 | node2.next = node3 62 | node3.next = node4 63 | node4.next = node5 64 | let head = solution.ReverseList(node1) 65 | XCTAssertEqual(head?.value, 5) 66 | XCTAssertEqual(head?.next?.value, 4) 67 | XCTAssertEqual(head?.next?.next?.value, 3) 68 | XCTAssertEqual(head?.next?.next?.next?.value, 2) 69 | XCTAssertEqual(head?.next?.next?.next?.next?.value, 1) 70 | } 71 | //1个节点 72 | func testCase2(){ 73 | let node1:ListNode = ListNode(value: 1, next: nil) 74 | let head = solution.ReverseList(node1) 75 | XCTAssertEqual(head?.value, 1) 76 | } 77 | //空链表 78 | func testCase3(){ 79 | let head = solution.ReverseList(nil) 80 | XCTAssertNil(head) 81 | } 82 | 83 | } 84 | 85 | UnitTests.defaultTestSuite.run() 86 | -------------------------------------------------------------------------------- /24_ReverseList.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /25_MergeSortedLists.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | //================================================================== 2 | // 《剑指Offer——名企面试官精讲典型编程题》代码 3 | //================================================================== 4 | // 面试题25:合并两个排序的链表 5 | // 题目:输入两个递增排序的链表,合并这两个链表并使新链表中的结点仍然是按 6 | // 照递增排序的。例如输入如下链表1和链表2,则合并之后的升序链表如链 7 | // 表3所示。 8 | // 链表1:1->3->5->7 9 | // 链表2:2->4->6->8 10 | // 链表3:1->2->3->4->5->6->7->8 11 | 12 | import Foundation 13 | import XCTest 14 | 15 | //定义链表节点 16 | class ListNode { 17 | var next: ListNode? 18 | var value: Int 19 | 20 | init(value: Int, next: ListNode?) { 21 | self.value = value 22 | self.next = next 23 | } 24 | } 25 | 26 | class Solution { 27 | /** 28 | 合并两个排序链表,并仍旧有序 29 | - Parameters: 30 | - node1: 链表1的头结点 31 | - node2: 链表2的头结点 32 | - Returns: 合并后的链表头节点 33 | */ 34 | func Merge(_ node1: ListNode?, _ node2: ListNode?) -> ListNode? { 35 | if node1 == nil { 36 | return node2 37 | } else if node2 == nil { 38 | return node1 39 | } 40 | var newHead: ListNode? = nil 41 | if node1!.value < node2!.value { 42 | newHead = node1 43 | newHead?.next = Merge(node1?.next, node2) 44 | } else { 45 | newHead = node2 46 | newHead?.next = Merge(node1, node2?.next) 47 | } 48 | return newHead 49 | } 50 | } 51 | 52 | class UnitTests: XCTestCase { 53 | var solution: Solution! 54 | 55 | override func setUp() { 56 | super.setUp() 57 | solution = Solution() 58 | } 59 | //list1: 1->3->5 60 | //list2: 2->4->6 61 | func testCase1(){ 62 | let node1:ListNode = ListNode(value: 1, next: nil) 63 | let node3:ListNode = ListNode(value: 3, next: nil) 64 | let node5:ListNode = ListNode(value: 5, next: nil) 65 | node1.next = node3 66 | node3.next = node5 67 | 68 | let node2:ListNode = ListNode(value: 2, next: nil) 69 | let node4:ListNode = ListNode(value: 4, next: nil) 70 | let node6:ListNode = ListNode(value: 6, next: nil) 71 | node2.next = node4 72 | node4.next = node6 73 | 74 | let head = solution.Merge(node1, node2) 75 | XCTAssertEqual(head?.value, 1) 76 | XCTAssertEqual(head?.next?.value, 2) 77 | XCTAssertEqual(head?.next?.next?.value, 3) 78 | XCTAssertEqual(head?.next?.next?.next?.value, 4) 79 | XCTAssertEqual(head?.next?.next?.next?.next?.value, 5) 80 | XCTAssertEqual(head?.next?.next?.next?.next?.next?.value, 6) 81 | } 82 | //list1: 1->3->5 83 | //list2: 1->3->5 84 | func testCase2(){ 85 | let node1:ListNode = ListNode(value: 1, next: nil) 86 | let node3:ListNode = ListNode(value: 3, next: nil) 87 | let node5:ListNode = ListNode(value: 5, next: nil) 88 | node1.next = node3 89 | node3.next = node5 90 | 91 | let node2:ListNode = ListNode(value: 1, next: nil) 92 | let node4:ListNode = ListNode(value: 3, next: nil) 93 | let node6:ListNode = ListNode(value: 5, next: nil) 94 | node2.next = node4 95 | node4.next = node6 96 | 97 | let head = solution.Merge(node1, node2) 98 | XCTAssertEqual(head?.value, 1) 99 | XCTAssertEqual(head?.next?.value, 1) 100 | XCTAssertEqual(head?.next?.next?.value, 3) 101 | XCTAssertEqual(head?.next?.next?.next?.value, 3) 102 | XCTAssertEqual(head?.next?.next?.next?.next?.value, 5) 103 | XCTAssertEqual(head?.next?.next?.next?.next?.next?.value, 5) 104 | } 105 | //list1: 1 106 | //list2: 2 107 | func testCase3(){ 108 | let node1:ListNode = ListNode(value: 1, next: nil) 109 | 110 | let node2:ListNode = ListNode(value: 2, next: nil) 111 | 112 | let head = solution.Merge(node1, node2) 113 | XCTAssertEqual(head?.value, 1) 114 | XCTAssertEqual(head?.next?.value, 2) 115 | } 116 | //list1: 1->3->5 117 | //list2: nil 118 | func testCase4(){ 119 | let node1:ListNode = ListNode(value: 1, next: nil) 120 | let node3:ListNode = ListNode(value: 3, next: nil) 121 | let node5:ListNode = ListNode(value: 5, next: nil) 122 | node1.next = node3 123 | node3.next = node5 124 | 125 | let head = solution.Merge(node1, nil) 126 | XCTAssertEqual(head?.value, 1) 127 | XCTAssertEqual(head?.next?.value, 3) 128 | XCTAssertEqual(head?.next?.next?.value, 5) 129 | } 130 | //list1: nil 131 | //list2: nil 132 | func testCase5(){ 133 | let head = solution.Merge(nil, nil) 134 | XCTAssertNil(head) 135 | } 136 | } 137 | 138 | UnitTests.defaultTestSuite.run() 139 | -------------------------------------------------------------------------------- /25_MergeSortedLists.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /26_SubstructureInTree.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /27_MirrorOfBinaryTree.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /28_SymmetricalBinaryTree.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /29_PrintMatrix.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /30_MinInStack.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | //================================================================== 2 | // 《剑指Offer——名企面试官精讲典型编程题》代码 3 | //================================================================== 4 | // 面试题30:包含min函数的栈 5 | // 题目:定义栈的数据结构,请在该类型中实现一个能够得到栈的最小元素的min 6 | // 函数。在该栈中,调用min、push及pop的时间复杂度都是O(1)。 7 | 8 | import Foundation 9 | import XCTest 10 | 11 | struct StackWithMin { 12 | private var dataArray = Array() //数据栈 13 | private var minArray = Array() //辅助栈,存放数据栈历次push元素后的最小元素,数据栈pop之后同样也pop该栈的元素 14 | /** 15 | 元素入栈 16 | - Parameters: 17 | - value: 入栈的元素 18 | */ 19 | mutating func push(_ value: T){ 20 | dataArray.append(value) 21 | //当新元素比之前的最小元素小时,把新元素插入辅助栈里 22 | //否则把之前的最小元素重复插入辅助栈里 23 | if minArray.count == 0 || value < minArray.last! { 24 | minArray.append(value) 25 | } else { 26 | minArray.append(minArray.last!) 27 | } 28 | } 29 | /** 30 | 元素出栈 31 | - Returns: 出栈的元素 32 | */ 33 | mutating func pop() -> T? { 34 | if dataArray.count > 0 && minArray.count > 0 { 35 | minArray.removeLast() 36 | return dataArray.removeLast() 37 | } 38 | return nil 39 | } 40 | /** 41 | 返回栈的最小值 42 | - Returns: 最小值的元素 43 | */ 44 | func min() -> T? { 45 | return minArray.last 46 | } 47 | /** 48 | 获取栈顶的元素 49 | - Returns: 栈顶元素 50 | */ 51 | func top() -> T? { 52 | return dataArray.last 53 | } 54 | /** 55 | 判断栈是否为空 56 | - Returns: 判断栈是否为空 57 | */ 58 | func empty() -> Bool { 59 | return dataArray.isEmpty 60 | } 61 | /** 62 | 返回栈大小 63 | - Returns: 栈大小 64 | */ 65 | func size() -> Int { 66 | return dataArray.count 67 | } 68 | 69 | } 70 | 71 | class UnitTests: XCTestCase { 72 | 73 | override func setUp() { 74 | super.setUp() 75 | } 76 | 77 | func testCase1() { 78 | var stack = StackWithMin() 79 | stack.push(3) 80 | XCTAssertEqual(stack.min(), 3) 81 | stack.push(4) 82 | XCTAssertEqual(stack.min(), 3) 83 | stack.push(2) 84 | XCTAssertEqual(stack.min(), 2) 85 | stack.push(3) 86 | XCTAssertEqual(stack.min(), 2) 87 | stack.pop() 88 | XCTAssertEqual(stack.min(), 2) 89 | stack.pop() 90 | XCTAssertEqual(stack.min(), 3) 91 | stack.pop() 92 | XCTAssertEqual(stack.min(), 3) 93 | stack.push(0) 94 | XCTAssertEqual(stack.min(), 0) 95 | } 96 | } 97 | 98 | UnitTests.defaultTestSuite.run() 99 | -------------------------------------------------------------------------------- /30_MinInStack.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /31_StackPushPopOrder.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | //================================================================== 2 | // 《剑指Offer——名企面试官精讲典型编程题》代码 3 | //================================================================== 4 | // 面试题31:栈的压入、弹出序列 5 | // 题目:输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是 6 | // 否为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1、2、3、4、 7 | // 5是某栈的压栈序列,序列4、5、3、2、1是该压栈序列对应的一个弹出序列,但 8 | // 4、3、5、1、2就不可能是该压栈序列的弹出序列。 9 | 10 | import Foundation 11 | import XCTest 12 | 13 | class Solution { 14 | /** 15 | 基于入栈序列判断出栈序列是否可能 16 | - Parameters: 17 | - pushList: 入栈序列 18 | - popList: 出栈序列 19 | - Returns: 是否为该栈的弹出序列 20 | */ 21 | func isPopOrder(pushList:[Int], popList:[Int]) -> Bool { 22 | var result = false 23 | guard pushList.count == popList.count && pushList.count > 0 else { 24 | return result 25 | } 26 | //辅助栈(用数组替代) 27 | var tmpArray = [Int]() 28 | var pushCount = 0 29 | var popCount = 0 30 | while popCount < popList.count { 31 | while tmpArray.isEmpty || tmpArray.last != popList[popCount] { 32 | if pushCount == pushList.count { 33 | break 34 | } 35 | tmpArray.append(pushList[pushCount]) 36 | pushCount += 1 37 | } 38 | if tmpArray.last != popList[popCount] { 39 | break 40 | } 41 | tmpArray.removeLast() 42 | popCount += 1 43 | } 44 | if tmpArray.isEmpty && popCount == popList.count { 45 | result = true 46 | } 47 | return result 48 | } 49 | } 50 | class UnitTests: XCTestCase { 51 | var solution: Solution! 52 | 53 | override func setUp() { 54 | super.setUp() 55 | solution = Solution() 56 | } 57 | 58 | func testCase1() { 59 | XCTAssertTrue(solution.isPopOrder(pushList: [1,2,3,4,5], popList: [4,5,3,2,1])) 60 | } 61 | func testCase2() { 62 | XCTAssertTrue(solution.isPopOrder(pushList: [1,2,3,4,5], popList: [3,5,4,2,1])) 63 | } 64 | func testCase3() { 65 | XCTAssertFalse(solution.isPopOrder(pushList: [1,2,3,4,5], popList: [4,3,5,1,2])) 66 | } 67 | func testCase4() { 68 | XCTAssertFalse(solution.isPopOrder(pushList: [1,2,3,4,5], popList: [3,5,4,1,2])) 69 | } 70 | func testCase5() { 71 | XCTAssertFalse(solution.isPopOrder(pushList: [1], popList: [2])) 72 | } 73 | func testCase6() { 74 | XCTAssertTrue(solution.isPopOrder(pushList: [1], popList: [1])) 75 | } 76 | } 77 | 78 | UnitTests.defaultTestSuite.run() 79 | -------------------------------------------------------------------------------- /31_StackPushPopOrder.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /32_01_PrintTreeFromTopToBottom.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | //================================================================== 2 | // 《剑指Offer——名企面试官精讲典型编程题》代码 3 | //================================================================== 4 | // 面试题32(一):不分行从上往下打印二叉树 5 | // 题目:从上往下打印出二叉树的每个结点,同一层的结点按照从左到右的顺序打印。 6 | 7 | import Foundation 8 | import XCTest 9 | 10 | //二叉树结构 11 | class BinaryTreeNode: Equatable { 12 | var parent: BinaryTreeNode? 13 | var left: BinaryTreeNode? 14 | var right: BinaryTreeNode? 15 | var value: Int 16 | 17 | init(value: Int, parent: BinaryTreeNode?, left: BinaryTreeNode?, right: BinaryTreeNode?) { 18 | self.value = value 19 | self.parent = parent 20 | self.left = left 21 | self.right = right 22 | } 23 | static func ==(left: BinaryTreeNode, right: BinaryTreeNode) -> Bool { 24 | return left.value == right.value 25 | } 26 | } 27 | 28 | class Solution { 29 | /** 30 | 按从上到下从左到右的顺序返回二叉树所有节点的值 31 | - Parameters: 32 | - root: 二叉树根节点 33 | - Returns: 二叉树的所有节点值 34 | */ 35 | func PrintFromTopToBottom(_ root: BinaryTreeNode) -> [Int] { 36 | var result = [Int]() 37 | var queue = [BinaryTreeNode]() 38 | queue.append(root) 39 | while queue.count > 0 { 40 | let node = queue.first! 41 | result.append(node.value) 42 | if node.left != nil { 43 | queue.append(node.left!) 44 | } 45 | if node.right != nil { 46 | queue.append(node.right!) 47 | } 48 | queue.remove(at: 0) 49 | } 50 | return result 51 | } 52 | } 53 | class UnitTests: XCTestCase { 54 | var solution: Solution! 55 | 56 | override func setUp() { 57 | super.setUp() 58 | solution = Solution() 59 | } 60 | // 10 61 | // / \ 62 | // 6 14 63 | // /\ /\ 64 | // 4 8 12 16 65 | func testCase1() { 66 | let node_1 = BinaryTreeNode(value: 10, parent: nil, left: nil, right: nil) 67 | let node_2 = BinaryTreeNode(value: 6, parent: node_1, left: nil, right: nil) 68 | let node_3 = BinaryTreeNode(value: 14, parent: node_1, left: nil, right: nil) 69 | let node_4 = BinaryTreeNode(value: 4, parent: node_2, left: nil, right: nil) 70 | let node_5 = BinaryTreeNode(value: 8, parent: node_2, left: nil, right: nil) 71 | let node_6 = BinaryTreeNode(value: 12, parent: node_3, left: nil, right: nil) 72 | let node_7 = BinaryTreeNode(value: 16, parent: node_3, left: nil, right: nil) 73 | node_1.left = node_2 74 | node_1.right = node_3 75 | node_2.left = node_4 76 | node_2.right = node_5 77 | node_3.left = node_6 78 | node_3.right = node_7 79 | XCTAssertEqual(solution.PrintFromTopToBottom(node_1), [10,6,14,4,8,12,16]) 80 | } 81 | // 5 82 | // / 83 | // 4 84 | // / 85 | // 3 86 | // / 87 | // 2 88 | // / 89 | // 1 90 | func testCase2(){ 91 | let node_1 = BinaryTreeNode(value: 5, parent: nil, left: nil, right: nil) 92 | let node_2 = BinaryTreeNode(value: 4, parent: node_1, left: nil, right: nil) 93 | let node_3 = BinaryTreeNode(value: 3, parent: node_2, left: nil, right: nil) 94 | let node_4 = BinaryTreeNode(value: 2, parent: node_3, left: nil, right: nil) 95 | let node_5 = BinaryTreeNode(value: 1, parent: node_4, left: nil, right: nil) 96 | node_1.left = node_2 97 | node_2.left = node_3 98 | node_3.left = node_4 99 | node_4.left = node_5 100 | XCTAssertEqual(solution.PrintFromTopToBottom(node_1), [5,4,3,2,1]) 101 | } 102 | // 1 103 | // \ 104 | // 2 105 | // \ 106 | // 3 107 | // \ 108 | // 4 109 | // \ 110 | // 5 111 | func testCase3(){ 112 | let node_1 = BinaryTreeNode(value: 1, parent: nil, left: nil, right: nil) 113 | let node_2 = BinaryTreeNode(value: 2, parent: node_1, left: nil, right: nil) 114 | let node_3 = BinaryTreeNode(value: 3, parent: node_2, left: nil, right: nil) 115 | let node_4 = BinaryTreeNode(value: 4, parent: node_3, left: nil, right: nil) 116 | let node_5 = BinaryTreeNode(value: 5, parent: node_4, left: nil, right: nil) 117 | node_1.right = node_2 118 | node_2.right = node_3 119 | node_3.right = node_4 120 | node_4.right = node_5 121 | XCTAssertEqual(solution.PrintFromTopToBottom(node_1), [1,2,3,4,5]) 122 | } 123 | // 树中只有1个结点 124 | func testCase4(){ 125 | let node_1 = BinaryTreeNode(value: 1, parent: nil, left: nil, right: nil) 126 | XCTAssertEqual(solution.PrintFromTopToBottom(node_1), [1]) 127 | } 128 | } 129 | 130 | UnitTests.defaultTestSuite.run() 131 | -------------------------------------------------------------------------------- /32_01_PrintTreeFromTopToBottom.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /32_02_PrintTreesInLines.playground.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /32_03_PrintTreesInZigzag.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /33_SquenceOfBST.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | //================================================================== 2 | // 《剑指Offer——名企面试官精讲典型编程题》代码 3 | //================================================================== 4 | // 面试题33:二叉搜索树的后序遍历序列 5 | // 题目:输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。 6 | // 如果是则返回true,否则返回false。假设输入的数组的任意两个数字都互不相同。 7 | 8 | import Foundation 9 | import XCTest 10 | 11 | class Solution { 12 | 13 | /** 14 | 判断输入的数组是否是某二叉搜索树的后序遍历序列 15 | - Parameters: 16 | - sequence: 数组 17 | - Returns: 判断结果 18 | */ 19 | func VerifySquenceOfBST(_ sequence: [Int]) -> Bool { 20 | guard sequence.count > 0 else { 21 | return false 22 | } 23 | let root = sequence.last! 24 | // 二叉搜索树左子树的节点小于根节点 25 | var i = 0 26 | while i < sequence.count - 1 { 27 | if sequence[i] > root { 28 | break 29 | } 30 | i += 1 31 | } 32 | // 二叉搜索树右子树的节点大于根节点 33 | var j = i 34 | while j < sequence.count - 1 { 35 | if sequence[j] < root { 36 | return false 37 | } 38 | j += 1 39 | } 40 | //递归判断左子树是不是二叉搜索树 41 | var left = true 42 | if i > 0 { 43 | left = VerifySquenceOfBST(Array(sequence[0.. 2 | 3 | 4 | -------------------------------------------------------------------------------- /34_PathInTree.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /35_CopyComplexList.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /36_ConvertBinarySearchTree.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /37_SerializeBinaryTrees.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /38_StringPermutation.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | //================================================================== 2 | // 《剑指Offer——名企面试官精讲典型编程题》代码 3 | //================================================================== 4 | // 面试题38:字符串的排列 5 | // 题目:输入一个字符串,打印出该字符串中字符的所有排列。例如输入字符串abc, 6 | // 则打印出由字符a、b、c所能排列出来的所有字符串abc、acb、bac、bca、cab和cba。 7 | 8 | import Foundation 9 | import XCTest 10 | 11 | class Solution { 12 | /** 13 | 返回该字符串中字符的所有排列 14 | - Parameters: 15 | - str: 输入的字符串 16 | - Returns: 字符所有可能的排列 17 | */ 18 | func Permutation(_ str: String) -> [String]{ 19 | let chars = Array(str) 20 | if chars.count == 0 { 21 | return [String]() 22 | } 23 | var result = [String]() 24 | Permutation(chars, startIndex: 0, result: &result) 25 | return result 26 | } 27 | /** 28 | 返回该字符串中字符的所有排列 29 | - Parameters: 30 | - chars: 字符数组 31 | - startIndex: 开始排列的数组索引 32 | - Returns: 字符所有可能的排列 33 | */ 34 | private func Permutation(_ chars:[Character], startIndex: Int, result: inout [String]){ 35 | var chars = chars 36 | if startIndex == chars.count { 37 | result.append(String(chars)) 38 | } else { 39 | for index in startIndex.. 2 | 3 | 4 | -------------------------------------------------------------------------------- /39_MoreThanHalfNumber.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | //================================================================== 2 | // 《剑指Offer——名企面试官精讲典型编程题》代码 3 | //================================================================== 4 | // 面试题39:数组中出现次数超过一半的数字 5 | // 题目:数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例 6 | // 如输入一个长度为9的数组{1, 2, 3, 2, 2, 2, 5, 4, 2}。由于数字2在数组中 7 | // 出现了5次,超过数组长度的一半,因此输出2。 8 | 9 | import Foundation 10 | import XCTest 11 | 12 | class Solution { 13 | /** 14 | 验证数组中是否出现一半以上的指定数字 15 | - Parameters: 16 | - nums: 数组 17 | - num: 指定数字 18 | - Returns: 验证结果 19 | */ 20 | private func checkMoreThanHalf(_ nums: [Int], num: Int) -> Bool { 21 | return nums.filter { $0 == num }.count * 2 <= nums.count ? false : true 22 | } 23 | 24 | /** 25 | 找出数组中出现次数超过一半的数字 26 | 解法:将数组排序(不一定要完全排序,利用快排原理,只要找到中位数即可),如果某个数字的次数超过数组长度一半,那么该数字必然是数组中间的那个数字 27 | - Parameters: 28 | - nums: 数组 29 | - Returns: 出现次数超过数组长度一半的数字 30 | */ 31 | func MoreThanHalfNum_Solution1(_ nums: [Int]) -> Int? { 32 | if nums.count == 0 { 33 | return nil 34 | } 35 | var nums = nums 36 | let middle = nums.count / 2 37 | 38 | var start = 0 39 | var end = nums.count - 1 40 | 41 | var p = partition(&nums, start: start, end: end) 42 | while p != middle { 43 | if p > middle { 44 | end = p - 1 45 | } else { 46 | start = p + 1 47 | } 48 | p = partition(&nums, start: start, end: end) 49 | } 50 | let median = nums[middle] 51 | return checkMoreThanHalf(nums, num: median) ? median : nil 52 | } 53 | 54 | /** 55 | 将数组在指定范围内[start,end]分区,使得左边部分数字比右边部分的小 56 | - Parameters: 57 | - nums: 数组 58 | - start: 分区开始索引 59 | - end: 分区结束索引 60 | - Returns: index:当前分区的分界索引 61 | */ 62 | func partition (_ nums: inout [Int], start: Int, end: Int) -> Int { 63 | if nums.count == 0 || start > end { 64 | return start 65 | } 66 | let pivot = nums[start] 67 | var lo = start + 1 68 | var hi = end 69 | 70 | while true { 71 | while nums[lo] <= pivot && lo < end { 72 | lo += 1 73 | } 74 | while nums[hi] > pivot { 75 | hi -= 1 76 | } 77 | if lo < hi { 78 | (nums[lo], nums[hi]) = (nums[hi], nums[lo]) 79 | } else { 80 | (nums[start], nums[hi]) = (nums[hi], nums[start]) 81 | return hi 82 | } 83 | } 84 | } 85 | /** 86 | 找出数组中出现次数超过一半的数字 87 | 解法:保存数组第一个数字result和次数times 88 | 从index=1开始遍历数组,如果数字与result相同,times+1,否则times-1 89 | 如果times=0, result保存下一个遍历数字,times重置为1 90 | **我们要找的数字出现的次数其他数字次数的和都多,所以要找的数字肯定是最后把次数设为1的数字** 91 | - Parameters: 92 | - nums: 数组 93 | - Returns: 出现次数超过数组长度一半的数字 94 | */ 95 | func MoreThanHalfNum_Solution2(_ nums: [Int]) -> Int? { 96 | if nums.count == 0 { 97 | return nil 98 | } 99 | var result = nums[0] 100 | var times = 1 101 | for num in nums[1...] { 102 | if times == 0 { 103 | result = num 104 | times = 1 105 | } else if num == result { 106 | times += 1 107 | } else { 108 | times -= 1 109 | } 110 | } 111 | return checkMoreThanHalf(nums, num: result) ? result : nil 112 | } 113 | } 114 | 115 | class UnitTests: XCTestCase { 116 | var solution: Solution! 117 | 118 | override func setUp() { 119 | super.setUp() 120 | solution = Solution() 121 | } 122 | //存在超过一半的数字 123 | func testCase1() { 124 | let nums = [1,2,3,2,2,2,5,4,2] 125 | XCTAssertEqual(2, solution.MoreThanHalfNum_Solution1(nums)) 126 | XCTAssertEqual(2, solution.MoreThanHalfNum_Solution2(nums)) 127 | } 128 | //不存在超过一半的数字 129 | func testCase2() { 130 | let nums = [1,2,3,2,4,2,5,2,3] 131 | XCTAssertEqual(nil, solution.MoreThanHalfNum_Solution1(nums)) 132 | XCTAssertEqual(nil, solution.MoreThanHalfNum_Solution2(nums)) 133 | } 134 | //存在超过一半的数字(该数字全部出现在数组前半部分) 135 | func testCase3() { 136 | let nums = [2,2,2,2,2,1,3,4,5] 137 | XCTAssertEqual(2, solution.MoreThanHalfNum_Solution1(nums)) 138 | XCTAssertEqual(2, solution.MoreThanHalfNum_Solution2(nums)) 139 | } 140 | //存在超过一半的数字(该数字全部出现在数组后半部分) 141 | func testCase4() { 142 | let nums = [1,3,4,5,2,2,2,2,2] 143 | XCTAssertEqual(2, solution.MoreThanHalfNum_Solution1(nums)) 144 | XCTAssertEqual(2, solution.MoreThanHalfNum_Solution2(nums)) 145 | } 146 | } 147 | 148 | UnitTests.defaultTestSuite.run() 149 | -------------------------------------------------------------------------------- /39_MoreThanHalfNumber.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /40_KLeastNumbers.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | //================================================================== 2 | // 《剑指Offer——名企面试官精讲典型编程题》代码 3 | //================================================================== 4 | // 面试题40:最小的k个数 5 | // 题目:输入n个整数,找出其中最小的k个数。例如输入4、5、1、6、2、7、3、8 6 | // 这8个数字,则最小的4个数字是1、2、3、4。 7 | 8 | import Foundation 9 | import XCTest 10 | 11 | class Solution { 12 | 13 | /** 14 | 输入n个整数,找出其中最小的k个数。 15 | 解法:通过partition的方式找出 16 | - Parameters: 17 | - nums: 数组 18 | - k: k 19 | - Returns: 最小的K个数 20 | */ 21 | func GetLeastNumbers_Solution1(_ nums: [Int], k: Int) -> [Int] { 22 | var nums = nums 23 | if nums.count == 0 || k <= 0 || k > nums.count{ 24 | return [Int]() 25 | } 26 | var start = 0 27 | var end = nums.count - 1 28 | 29 | var p = partition(&nums, start: start, end: end) 30 | 31 | while p != k - 1 { 32 | if p > k - 1 { 33 | end = p - 1 34 | } else { 35 | start = p + 1 36 | } 37 | p = partition(&nums, start: start, end: end) 38 | 39 | } 40 | return Array(nums[.. Int { 51 | if nums.count == 0 || start >= end { 52 | return start 53 | } 54 | 55 | let pivot = nums[start] 56 | var lo = start + 1 57 | var hi = end 58 | 59 | while true { 60 | while nums[lo] <= pivot && lo < end { 61 | lo += 1 62 | } 63 | while nums[hi] > pivot { 64 | hi -= 1 65 | } 66 | if lo < hi { 67 | (nums[lo], nums[hi]) = (nums[hi], nums[lo]) 68 | } else { 69 | (nums[start], nums[hi]) = (nums[hi], nums[start]) 70 | return hi 71 | } 72 | } 73 | } 74 | 75 | /** 76 | 输入n个整数,找出其中最小的k个数。 77 | 解法:遍历数组,使用一个最大堆保存最小的k个数(不改变数组,不用一次性全部加载数据,所以适合大数据处理) 78 | - Parameters: 79 | - nums: n个整数 80 | - k: k 81 | - Returns: 最小的k个数 82 | */ 83 | func GetLeastNumbers_Solution2(_ nums: [Int], k: Int) -> [Int] { 84 | var heap = Heap(sort: >) 85 | for num in nums { 86 | if heap.count < k { 87 | heap.insert(num) 88 | continue 89 | } 90 | if num < heap.peek()! { 91 | heap.remove() 92 | heap.insert(num) 93 | } 94 | } 95 | var result = [Int]() 96 | for _ in 0.. 2 | 3 | 4 | -------------------------------------------------------------------------------- /41_StreamMedian.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | //================================================================== 2 | // 《剑指Offer——名企面试官精讲典型编程题》代码 3 | //================================================================== 4 | // 面试题41:数据流中的中位数 5 | // 题目:如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么 6 | // 中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值, 7 | // 那么中位数就是所有数值排序之后中间两个数的平均值。 8 | 9 | import Foundation 10 | import XCTest 11 | 12 | class Solution { 13 | 14 | /** 15 | 获取数据流中的中位数 16 | - Parameters: 17 | - nums: n个数 18 | - Returns: 中位数 19 | */ 20 | func GetMedian(_ nums: [Double]) -> Double? { 21 | if nums.count == 0 { return nil } 22 | var maxHeap = Heap(sort: >) 23 | var minHeap = Heap(sort: <) 24 | //将数据分别插入到最大堆和最小堆中 25 | for num in nums { 26 | if (maxHeap.count + minHeap.count) % 2 == 0 { 27 | //1.两个堆的总数和为偶数,需要将数据插入至最小堆 28 | //1.1 如果该数比最大堆的数还要小,则需要先插入最大堆,然后把最大堆的最大数(root)插入到最小堆 29 | //1.2 否则,直接插入最小堆 30 | var insertToMinHeap = num 31 | if maxHeap.count > 0 && num < maxHeap.peek()! { 32 | insertToMinHeap = maxHeap.peek()! 33 | maxHeap.insert(num) 34 | maxHeap.remove() 35 | } 36 | minHeap.insert(insertToMinHeap) 37 | } else { 38 | //2.两个堆的总数和为奇数,需要插入至最大堆 39 | //2.1 如果该数比最小堆的数还要大,则需要先插入最小堆,然后把最小堆的最小数(root)插入到最大堆 40 | //2.2 否则,直接插入最大堆 41 | var insertToMaxHeap = num 42 | if minHeap.count > 0 && num > minHeap.peek()! { 43 | insertToMaxHeap = minHeap.peek()! 44 | minHeap.insert(num) 45 | minHeap.remove() 46 | } 47 | maxHeap.insert(insertToMaxHeap) 48 | } 49 | } 50 | //开始获取中位数 51 | let size = minHeap.count + maxHeap.count 52 | if size % 2 == 0 { 53 | //两堆总数一致,取平均数 54 | return (minHeap.peek()! + Double(maxHeap.peek()!)) / 2.0 55 | } else { 56 | return minHeap.peek() 57 | } 58 | } 59 | 60 | } 61 | 62 | class UnitTests: XCTestCase { 63 | var solution: Solution! 64 | 65 | override func setUp() { 66 | super.setUp() 67 | solution = Solution() 68 | } 69 | 70 | func testCase1() { 71 | XCTAssertEqual(solution.GetMedian([5]), 5) 72 | XCTAssertEqual(solution.GetMedian([5,2]), 3.5) 73 | XCTAssertEqual(solution.GetMedian([5,2,3]), 3) 74 | XCTAssertEqual(solution.GetMedian([5,2,3,4]), 3.5) 75 | XCTAssertEqual(solution.GetMedian([5,2,3,4,1]), 3) 76 | XCTAssertEqual(solution.GetMedian([5,2,3,4,1,6]), 3.5) 77 | XCTAssertEqual(solution.GetMedian([5,2,3,4,1,6,7]), 4) 78 | XCTAssertEqual(solution.GetMedian([5,2,3,4,1,6,7,0]), 3.5) 79 | XCTAssertEqual(solution.GetMedian([5,2,3,4,1,6,7,0,8]), 4) 80 | } 81 | } 82 | 83 | UnitTests.defaultTestSuite.run() 84 | -------------------------------------------------------------------------------- /41_StreamMedian.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /42_GreatestSumOfSubarrays.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | //================================================================== 2 | // 《剑指Offer——名企面试官精讲典型编程题》代码 3 | //================================================================== 4 | // 面试题42:连续子数组的最大和 5 | // 题目:输入一个整型数组,数组里有正数也有负数。数组中一个或连续的多个整 6 | // 数组成一个子数组。求所有子数组的和的最大值。要求时间复杂度为O(n)。 7 | 8 | import Foundation 9 | import XCTest 10 | 11 | class Solution { 12 | 13 | /** 14 | 连续子数组的最大和 15 | - Parameters: 16 | - nums: n个数的数组 17 | - Returns: 最大和 18 | */ 19 | func FindGreatestSumOfSubArray(_ nums: [Int]) -> Int { 20 | if nums.count == 0 { return 0 } 21 | var currentSum = 0 22 | var maxSum = Int.min 23 | for num in nums { 24 | if currentSum <= 0 { 25 | currentSum = num 26 | } else { 27 | currentSum += num 28 | } 29 | if currentSum > maxSum { 30 | maxSum = currentSum 31 | } 32 | } 33 | return maxSum 34 | } 35 | } 36 | 37 | class UnitTests: XCTestCase { 38 | var solution: Solution! 39 | 40 | override func setUp() { 41 | super.setUp() 42 | solution = Solution() 43 | } 44 | //有正数有负数 45 | func testCase1() { 46 | XCTAssertEqual(18, solution.FindGreatestSumOfSubArray([1,-2,3,10,-4,7,2,-5])) 47 | } 48 | //全是负数 49 | func testCase2() { 50 | XCTAssertEqual(-1, solution.FindGreatestSumOfSubArray([-2,-8,-1,-5,-9])) 51 | } 52 | //全是正数 53 | func testCase3() { 54 | XCTAssertEqual(25, solution.FindGreatestSumOfSubArray([2,8,1,5,9])) 55 | } 56 | } 57 | 58 | UnitTests.defaultTestSuite.run() 59 | -------------------------------------------------------------------------------- /42_GreatestSumOfSubarrays.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /43_NumberOf1.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | //================================================================== 2 | // 《剑指Offer——名企面试官精讲典型编程题》代码 3 | //================================================================== 4 | // 面试题43:从1到n整数中1出现的次数 5 | // 题目:输入一个整数n,求从1到n这n个整数的十进制表示中1出现的次数。例如 6 | // 输入12,从1到12这些整数中包含1 的数字有1,10,11和12,1一共出现了5次。 7 | 8 | import Foundation 9 | import XCTest 10 | 11 | class Solution { 12 | 13 | /** 14 | 统计从1到N整数中1出现的次数 15 | - Parameters: 16 | - nums: 整数N 17 | - Returns: 1-N 的数十进制表示中1出现的次数 18 | 解法:遍历1-N,累计过程中每个数字中1出现的计数 19 | */ 20 | func NumberOf1Between1AndN_Solution1(N: Int) -> Int { 21 | if N <= 0 { return 0 } 22 | var totalCount = 0 23 | for i in 1...N { 24 | var count = 0 25 | var n = i 26 | while n > 0 { 27 | if n % 10 == 1 { 28 | count += 1 29 | } 30 | n = n / 10 31 | } 32 | totalCount += count 33 | } 34 | return totalCount 35 | } 36 | /** 37 | 统计从1到N整数中1出现的次数 38 | - Parameters: 39 | - nums: 整数N 40 | - Returns: 1-N 的数十进制表示中1出现的次数 41 | */ 42 | func NumberOf1Between1AndN_Solution2(N: Int) -> Int { 43 | if N <= 0 { return 0 } 44 | return NumberOf1(Array(String(N)).map { Int(String($0))! }) 45 | } 46 | /** 47 | 统计从1到N整数中1出现的次数 48 | - Parameters: 49 | - digits: 整数N的各位组成的数组 50 | - Returns: 1-N 的数十进制表示中1出现的次数 51 | */ 52 | private func NumberOf1(_ digits:[Int]) -> Int { 53 | if digits.count == 1 { return digits[0] > 0 ? 1 : 0 } //个位数,1只会出现1次 54 | //假如数组是[2,1,3,4,5] 55 | //numFirstDigit是数字10000-19999的第一位中1的数目 56 | var numFirstDigit = 0 57 | if digits[0] > 1{ 58 | numFirstDigit = PowerBase10(n: digits.count - 1) 59 | } else if digits[0] == 1 { 60 | numFirstDigit = Int(digits[1...].map(String.init).joined())! + 1 61 | } 62 | //numOtherDigits 是 01346 - 21345 除了第一位之外的数位中1的数目 63 | let numOtherDigits = digits[0] * (digits.count - 1) * PowerBase10(n: digits.count - 2) 64 | // numRecursive 是1-1345的数目,用递归求得 65 | let numRecursive = NumberOf1(Array(digits[1...])) 66 | return numFirstDigit + numOtherDigits + numRecursive 67 | } 68 | /** 69 | 计算10的n次方 70 | - Parameters: 71 | - n: n 72 | - Returns: 10的n次方结果 73 | */ 74 | private func PowerBase10(n: Int) -> Int { 75 | if n < 1 { return 1} 76 | var result = 1 77 | for _ in 0.. 2 | 3 | 4 | -------------------------------------------------------------------------------- /44_DigitsInSequence.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | //================================================================== 2 | // 《剑指Offer——名企面试官精讲典型编程题》代码 3 | //================================================================== 4 | // 面试题44:数字序列中某一位的数字 5 | // 题目:数字以0123456789101112131415…的格式序列化到一个字符序列中。在这 6 | // 个序列中,第5位(从0开始计数)是5,第13位是1,第19位是4,等等。请写一 7 | // 个函数求任意位对应的数字。 8 | 9 | import Foundation 10 | import XCTest 11 | 12 | class Solution { 13 | 14 | /** 15 | 数字以0123456789101112131415…的格式序列化到一个字符序列中。求第index位的数字 16 | - Parameters: 17 | - index: index 18 | - Returns: 对应的数字 19 | */ 20 | func digitAtIndex(_ index: Int) -> Int? { 21 | if index < 0 { return nil } 22 | var index = index 23 | var digits = 1 24 | while true { 25 | let numbers = countOfIntegers(with: digits) 26 | if index < numbers * digits { 27 | return digitAtIndex(index, digits) 28 | } 29 | index -= digits * numbers 30 | digits += 1 31 | } 32 | } 33 | 34 | /** 35 | 根据digits位数 返回整数个数 36 | 例如1位数字的整数有10个(0-9) 37 | 2位数字的整数有90个 (10-99) 38 | 3位数字的整数有900个(100-999) 39 | - Parameters: 40 | - digits: 位数 41 | - Returns: 位数是digits的整数个数 42 | */ 43 | private func countOfIntegers(with digits: Int) -> Int { 44 | if digits == 1 { return 10 } 45 | return 9 * Int(pow(Double(10), Double(digits - 1))) 46 | } 47 | 48 | /** 49 | 以digits位数的整数第一个数字的字符序列开始,取第index位的数字 50 | - Parameters: 51 | - index: 第index位 52 | - digits: 整数位数 53 | - Returns: digits位整数开始第index位数字 54 | */ 55 | private func digitAtIndex(_ index: Int, _ digits: Int) -> Int { 56 | var number = beginNumber(digits) + index / digits 57 | let indexFromRight = digits - index % digits; //表示digits位数中的第几位(从个位数开始数,也就是右边) 58 | for _ in 1.. Int { 74 | if digits == 1 { return 0 } 75 | return Int(pow(Double(10), Double(digits - 1))) 76 | } 77 | } 78 | 79 | class UnitTests: XCTestCase { 80 | var solution: Solution! 81 | override func setUp() { 82 | super.setUp() 83 | solution = Solution() 84 | } 85 | func testCase1() { 86 | XCTAssertEqual(0, solution.digitAtIndex(0)) 87 | XCTAssertEqual(1, solution.digitAtIndex(1)) 88 | XCTAssertEqual(9, solution.digitAtIndex(9)) 89 | XCTAssertEqual(1, solution.digitAtIndex(10)) 90 | XCTAssertEqual(9, solution.digitAtIndex(189)) // 99的最后一位,9 91 | XCTAssertEqual(1, solution.digitAtIndex(190)) //100的最后一位 0 92 | XCTAssertEqual(3, solution.digitAtIndex(1000)) //370的第一位,3 93 | XCTAssertEqual(7, solution.digitAtIndex(1001)) //370的第二位,7 94 | XCTAssertEqual(0, solution.digitAtIndex(1002)) //370的第三位 0 95 | } 96 | } 97 | 98 | UnitTests.defaultTestSuite.run() 99 | -------------------------------------------------------------------------------- /44_DigitsInSequence.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /45_SortArrayForMinNumber.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | //================================================================== 2 | // 《剑指Offer——名企面试官精讲典型编程题》代码 3 | //================================================================== 4 | // 面试题45:把数组排成最小的数 5 | // 题目:输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼 6 | // 接出的所有数字中最小的一个。例如输入数组{3, 32, 321},则打印出这3个数 7 | // 字能排成的最小数字321323。 8 | 9 | import Foundation 10 | import XCTest 11 | 12 | class Solution { 13 | 14 | /** 15 | 根据输入数组,返回数组里所有数字拼接起来能排成的最小数字 16 | - Parameters: 17 | - nums: 数组 18 | - Returns: 最小的数字 19 | */ 20 | func PrintMinNumber(_ nums: [Int]) -> Int? { 21 | if nums.count == 0 { return nil } 22 | let digitCount = nums.reduce(0, { x, y in 23 | x + String(y).count 24 | }) 25 | if digitCount > 10 { 26 | return nil 27 | } 28 | 29 | //核心解法:将问题转换为排序,然后将输入的数字转换成字符串,再将$0和$1进行拼接比较,小的排在前面 30 | let nums = nums.map{String($0)}.sorted{return $0+$1 < $1+$0 } 31 | let minNumber = nums.reduce("", {x, y in 32 | x + y 33 | }) 34 | return Int(minNumber) 35 | } 36 | } 37 | 38 | class UnitTests: XCTestCase { 39 | var solution: Solution! 40 | 41 | override func setUp() { 42 | super.setUp() 43 | solution = Solution() 44 | } 45 | 46 | func testCase1() { 47 | XCTAssertEqual(12345, solution.PrintMinNumber([3,5,1,4,2])) 48 | XCTAssertEqual(321323, solution.PrintMinNumber([3,32,321])) 49 | XCTAssertEqual(321233233, solution.PrintMinNumber([3,323,32123])) 50 | XCTAssertEqual(111111, solution.PrintMinNumber([1,11,111])) 51 | XCTAssertEqual(321, solution.PrintMinNumber([321])) 52 | } 53 | } 54 | 55 | UnitTests.defaultTestSuite.run() 56 | -------------------------------------------------------------------------------- /45_SortArrayForMinNumber.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /46_TranslateNumbersToStrings.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | //================================================================== 2 | // 《剑指Offer——名企面试官精讲典型编程题》代码 3 | //================================================================== 4 | // 面试题46:把数字翻译成字符串 5 | // 题目:给定一个数字,我们按照如下规则把它翻译为字符串:0翻译成"a",1翻 6 | // 译成"b",……,11翻译成"l",……,25翻译成"z"。一个数字可能有多个翻译。例 7 | // 如12258有5种不同的翻译,它们分别是"bccfi"、"bwfi"、"bczi"、"mcfi"和 8 | // "mzi"。请编程实现一个函数用来计算一个数字有多少种不同的翻译方法。 9 | 10 | import Foundation 11 | import XCTest 12 | 13 | class Solution { 14 | /** 15 | 求数字翻译成字符串的方法种数 16 | - Parameters: 17 | - number: 数字 18 | - Returns: 翻译方法种数 19 | 解法:从数字的右边往左边进行递归计算,消除重复计算的问题 20 | */ 21 | func GetTranslationCount(_ number: Int) -> Int { 22 | if number < 0 { return 0 } 23 | return GetTranslationCount(String(number).map{Int(String($0))!}) 24 | } 25 | /** 26 | 求数字翻译成字符串的方法种数 27 | - Parameters: 28 | - nums: 数字的各位拆成的数组 29 | - Returns: 翻译方法种数 30 | */ 31 | private func GetTranslationCount(_ nums: [Int]) -> Int { 32 | var counts: [Int:Int] = [:] //counts[i] 表示第i位到个位数组成数字的翻译方法次数 33 | for index in stride(from: nums.count - 1, through: 0, by: -1) { 34 | var count = 0 35 | if index < nums.count - 1 { 36 | count = counts[index + 1]! 37 | } else { 38 | count = 1 39 | } 40 | if index < nums.count - 1 { 41 | let digit1 = nums[index] 42 | let digit2 = nums[index + 1] 43 | let converted = digit1 * 10 + digit2 44 | if converted >= 10 && converted <= 25 { 45 | if index < nums.count - 2 { 46 | count += counts[index + 2]! 47 | } else { 48 | count += 1 49 | } 50 | } 51 | } 52 | counts[index] = count 53 | } 54 | return counts[0]! 55 | } 56 | } 57 | 58 | class UnitTests: XCTestCase { 59 | var solution: Solution! 60 | override func setUp() { 61 | super.setUp() 62 | solution = Solution() 63 | } 64 | func testCase1() { 65 | XCTAssertEqual(1, solution.GetTranslationCount(0)) 66 | XCTAssertEqual(2, solution.GetTranslationCount(10)) 67 | XCTAssertEqual(3, solution.GetTranslationCount(125)) 68 | XCTAssertEqual(2, solution.GetTranslationCount(126)) 69 | XCTAssertEqual(1, solution.GetTranslationCount(426)) 70 | XCTAssertEqual(2, solution.GetTranslationCount(100)) 71 | XCTAssertEqual(2, solution.GetTranslationCount(101)) 72 | XCTAssertEqual(5, solution.GetTranslationCount(12258)) 73 | XCTAssertEqual(0, solution.GetTranslationCount(-100)) 74 | } 75 | } 76 | 77 | UnitTests.defaultTestSuite.run() 78 | -------------------------------------------------------------------------------- /46_TranslateNumbersToStrings.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /47_MaxValueOfGifts.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | //================================================================== 2 | // 《剑指Offer——名企面试官精讲典型编程题》代码 3 | //================================================================== 4 | // 面试题47:礼物的最大价值 5 | // 题目:在一个m×n的棋盘的每一格都放有一个礼物,每个礼物都有一定的价值 6 | // (价值大于0)。你可以从棋盘的左上角开始拿格子里的礼物,并每次向右或 7 | // 者向下移动一格直到到达棋盘的右下角。给定一个棋盘及其上面的礼物,请计 8 | // 算你最多能拿到多少价值的礼物? 9 | 10 | import Foundation 11 | import XCTest 12 | 13 | class Solution { 14 | 15 | /** 16 | 求礼物的最大价值 17 | - Parameters: 18 | - gifts: 礼物的矩阵 19 | - Returns: 最大值 20 | 解法:遍历矩阵每个位置,计算当前位置最大礼物价值,根据移动特性,它由当前位置的左和上的两个元素的决定。 21 | */ 22 | func getMaxValue_solution1(_ matrix: [[Int]]) -> Int { 23 | if matrix.count == 0 { return 0 } 24 | var maxValues = [[Int]]() 25 | for (i, gifts) in matrix.enumerated() { 26 | maxValues.append([Int]()) 27 | for (j, gift) in gifts.enumerated() { 28 | maxValues[i].append(0) 29 | var left = 0 30 | var up = 0 31 | if i > 0 { 32 | up = maxValues[i - 1][j] 33 | } 34 | if j > 0 { 35 | left = maxValues[i][j-1] 36 | } 37 | maxValues[i][j] = max(left, up) + gift 38 | } 39 | } 40 | return maxValues.last!.last! 41 | } 42 | 43 | /** 44 | 求礼物的最大价值 45 | - Parameters: 46 | - gifts: 礼物的矩阵 47 | - Returns: 最大值 48 | 解法:遍历矩阵每个位置,计算当前位置最大礼物价值,根据移动特性,它由当前位置的左和上的两个元素的决定。 49 | 与解法1的区别是中间结果只需要一维数组即可 50 | */ 51 | func getMaxValue_solution2(_ matrix: [[Int]]) -> Int { 52 | if matrix.count == 0 { return 0 } 53 | var maxValues = [Int]() 54 | for (i, gifts) in matrix.enumerated() { 55 | for (j, gift) in gifts.enumerated() { 56 | if i == 0 { maxValues.append(0) } 57 | var left = 0 58 | var up = 0 59 | if i > 0 { 60 | up = maxValues[j] 61 | } 62 | if j > 0 { 63 | left = maxValues[j-1] 64 | } 65 | maxValues[j] = max(left, up) + gift 66 | } 67 | } 68 | return maxValues.last! 69 | } 70 | } 71 | 72 | class UnitTests: XCTestCase { 73 | var solution: Solution! 74 | 75 | override func setUp() { 76 | super.setUp() 77 | solution = Solution() 78 | } 79 | 80 | func testCase1() { 81 | let matrix = [[1,2,3],[4,5,6],[7,8,9]] 82 | XCTAssertEqual(29, solution.getMaxValue_solution1(matrix)) 83 | XCTAssertEqual(29, solution.getMaxValue_solution2(matrix)) 84 | } 85 | func testCase2() { 86 | let matrix = [[1,10,3,8],[12,2,9,6],[5,7,4,11],[3,7,16,5]] 87 | XCTAssertEqual(53, solution.getMaxValue_solution1(matrix)) 88 | XCTAssertEqual(53, solution.getMaxValue_solution2(matrix)) 89 | } 90 | func testCase3() { 91 | let matrix = [[1,10,3,8]] 92 | XCTAssertEqual(22, solution.getMaxValue_solution1(matrix)) 93 | XCTAssertEqual(22, solution.getMaxValue_solution2(matrix)) 94 | } 95 | func testCase4() { 96 | let matrix = [[1],[12],[5],[3]] 97 | XCTAssertEqual(21, solution.getMaxValue_solution1(matrix)) 98 | XCTAssertEqual(21, solution.getMaxValue_solution2(matrix)) 99 | } 100 | func testCase5() { 101 | let matrix = [[3]] 102 | XCTAssertEqual(3, solution.getMaxValue_solution1(matrix)) 103 | XCTAssertEqual(3, solution.getMaxValue_solution2(matrix)) 104 | } 105 | } 106 | 107 | UnitTests.defaultTestSuite.run() 108 | -------------------------------------------------------------------------------- /47_MaxValueOfGifts.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /48_LongestSubstringWithoutDup.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | //================================================================== 2 | // 《剑指Offer——名企面试官精讲典型编程题》代码 3 | //================================================================== 4 | // 面试题48:最长不含重复字符的子字符串 5 | // 题目:请从字符串中找出一个最长的不包含重复字符的子字符串,计算该最长子 6 | // 字符串的长度。假设字符串中只包含从'a'到'z'的字符。 7 | 8 | import Foundation 9 | import XCTest 10 | 11 | class Solution { 12 | 13 | /** 14 | 求最长不含重复字符的子字符串 15 | - Parameters: 16 | - str: 字符串 17 | - Returns: 最长的不包含重复字符的子字符串长度 18 | 解法:穷举法,验证所有的子字符串 19 | */ 20 | func longestSubstringWithoutDuplication_1(_ str: String) -> Int { 21 | var longest = 0 22 | var chars = Array(str) 23 | 24 | for i in stride(from: 0, to: chars.count, by: 1) { 25 | for j in stride(from: i, to: chars.count, by: 1) { 26 | if !hasDuplication(String(chars[i...j])) { 27 | let count = j - i + 1 28 | if count > longest { 29 | longest = count 30 | } 31 | } 32 | } 33 | } 34 | return longest 35 | } 36 | /** 37 | 判断字符串中是否包含重复字符 38 | - Parameters: 39 | - substring: 字符串 40 | - Returns: 判断结果 41 | */ 42 | private func hasDuplication(_ substring: String) -> Bool { 43 | let chars = Array(substring) 44 | var result = [Character]() 45 | for char in chars { 46 | if result.contains(char) { 47 | return true 48 | } else { 49 | result.append(char) 50 | } 51 | } 52 | return false 53 | } 54 | 55 | /** 56 | 求最长不含重复字符的子字符串 57 | - Parameters: 58 | - str: 字符串 59 | - Returns: 最长的不包含重复字符的子字符串长度 60 | 解法:动态规划 61 | */ 62 | func longestSubstringWithoutDuplication_2(_ str: String) -> Int { 63 | var curLength = 0 64 | var maxLength = 0 65 | let chars = Array(str) 66 | var position = [Character:Int]() 67 | for (i, char) in chars.enumerated() { 68 | let prePosition = position[char] 69 | if prePosition == nil || i - prePosition! > curLength { 70 | curLength += 1 71 | } else { 72 | if curLength > maxLength { 73 | maxLength = curLength 74 | } 75 | curLength = i - prePosition! 76 | } 77 | position[char] = i 78 | } 79 | return max(curLength, maxLength) 80 | } 81 | } 82 | 83 | class UnitTests: XCTestCase { 84 | var solution: Solution! 85 | 86 | override func setUp() { 87 | super.setUp() 88 | solution = Solution() 89 | } 90 | 91 | func testCase1() { 92 | XCTAssertEqual(4, solution.longestSubstringWithoutDuplication_1("abcacfrar")) 93 | XCTAssertEqual(4, solution.longestSubstringWithoutDuplication_2("abcacfrar")) 94 | } 95 | func testCase2() { 96 | XCTAssertEqual(4, solution.longestSubstringWithoutDuplication_1("acfrarabc")) 97 | XCTAssertEqual(4, solution.longestSubstringWithoutDuplication_2("acfrarabc")) 98 | } 99 | func testCase3() { 100 | XCTAssertEqual(4, solution.longestSubstringWithoutDuplication_1("arabcacfr")) 101 | XCTAssertEqual(4, solution.longestSubstringWithoutDuplication_2("arabcacfr")) 102 | } 103 | func testCase4() { 104 | XCTAssertEqual(1, solution.longestSubstringWithoutDuplication_1("aaa")) 105 | XCTAssertEqual(1, solution.longestSubstringWithoutDuplication_2("aaa")) 106 | } 107 | func testCase5() { 108 | XCTAssertEqual(7, solution.longestSubstringWithoutDuplication_1("abcdefg")) 109 | XCTAssertEqual(7, solution.longestSubstringWithoutDuplication_2("abcdefg")) 110 | } 111 | func testCase6() { 112 | XCTAssertEqual(2, solution.longestSubstringWithoutDuplication_1("aaabbbccc")) 113 | XCTAssertEqual(2, solution.longestSubstringWithoutDuplication_2("aaabbbccc")) 114 | } 115 | func testCase7() { 116 | XCTAssertEqual(4, solution.longestSubstringWithoutDuplication_1("abcdcba")) 117 | XCTAssertEqual(4, solution.longestSubstringWithoutDuplication_2("abcdcba")) 118 | } 119 | func testCase8() { 120 | XCTAssertEqual(6, solution.longestSubstringWithoutDuplication_1("abcdaef")) 121 | XCTAssertEqual(6, solution.longestSubstringWithoutDuplication_2("abcdaef")) 122 | } 123 | func testCase9() { 124 | XCTAssertEqual(1, solution.longestSubstringWithoutDuplication_1("a")) 125 | XCTAssertEqual(1, solution.longestSubstringWithoutDuplication_2("a")) 126 | } 127 | func testCase10() { 128 | XCTAssertEqual(0, solution.longestSubstringWithoutDuplication_1("")) 129 | XCTAssertEqual(0, solution.longestSubstringWithoutDuplication_2("")) 130 | } 131 | } 132 | 133 | UnitTests.defaultTestSuite.run() 134 | -------------------------------------------------------------------------------- /48_LongestSubstringWithoutDup.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /49_UglyNumber.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | //================================================================== 2 | // 《剑指Offer——名企面试官精讲典型编程题》代码 3 | //================================================================== 4 | // 面试题49:丑数 5 | // 题目:我们把只包含因子2、3和5的数称作丑数(Ugly Number)。求按从小到 6 | // 大的顺序的第1500个丑数。例如6、8都是丑数,但14不是,因为它包含因子7。 7 | // 习惯上我们把1当做第一个丑数。 8 | 9 | import Foundation 10 | import XCTest 11 | 12 | class Solution { 13 | 14 | /** 15 | 计算丑数 16 | - Parameters: 17 | - index: 返回第index个丑数 18 | - Returns: 丑数 19 | 解法:从0开始遍历判断是否丑数,直到计算到index个 20 | */ 21 | func getUglyNumber_Solution1(_ index: Int) -> Int { 22 | guard index > 0 else { 23 | return 0 24 | } 25 | var number = 0 26 | var uglyFound = 0 27 | while uglyFound < index { 28 | number += 1 29 | if isUglyNumber(number) { 30 | uglyFound += 1 31 | } 32 | } 33 | return number 34 | } 35 | /** 36 | 判断是否是丑数 37 | - Parameters: 38 | - number: 数字 39 | - Returns: 判断结果 40 | */ 41 | private func isUglyNumber(_ number: Int) -> Bool { 42 | var number = number 43 | while number % 2 == 0 { 44 | number /= 2 45 | } 46 | while number % 3 == 0 { 47 | number /= 3 48 | } 49 | while number % 5 == 0 { 50 | number /= 5 51 | } 52 | return number == 1 ? true : false 53 | } 54 | 55 | /** 56 | 计算丑数 57 | - Parameters: 58 | - index: 返回第index个丑数 59 | - Returns: 丑数 60 | 解法:根据已知的丑数,*2、*3、*5等方式计算下一个丑数 61 | */ 62 | func getUglyNumber_Solution2(_ index: Int) -> Int { 63 | guard index > 0 else { 64 | return 0 65 | } 66 | var uglyNumbers = [Int]() 67 | uglyNumbers.append(1) //第一个丑数是1 68 | var nextUglyIndex = 1 69 | var multiply2Index = 0, multiply3Index = 0, multiply5Index = 0 70 | while nextUglyIndex < index { 71 | let nextUglyNumber = min(uglyNumbers[multiply2Index] * 2, 72 | uglyNumbers[multiply3Index] * 3, 73 | uglyNumbers[multiply5Index] * 5) 74 | uglyNumbers.append(nextUglyNumber) 75 | while uglyNumbers[multiply2Index] * 2 <= uglyNumbers.last! { 76 | multiply2Index += 1 77 | } 78 | while uglyNumbers[multiply3Index] * 3 <= uglyNumbers.last! { 79 | multiply3Index += 1 80 | } 81 | while uglyNumbers[multiply5Index] * 5 <= uglyNumbers.last! { 82 | multiply5Index += 1 83 | } 84 | nextUglyIndex += 1 85 | } 86 | return uglyNumbers.last! 87 | } 88 | } 89 | 90 | class UnitTests: XCTestCase { 91 | var solution: Solution! 92 | 93 | override func setUp() { 94 | super.setUp() 95 | solution = Solution() 96 | } 97 | func testCase1() { 98 | XCTAssertEqual(1, solution.getUglyNumber_Solution1(1)) 99 | XCTAssertEqual(2, solution.getUglyNumber_Solution1(2)) 100 | XCTAssertEqual(3, solution.getUglyNumber_Solution1(3)) 101 | XCTAssertEqual(4, solution.getUglyNumber_Solution1(4)) 102 | XCTAssertEqual(5, solution.getUglyNumber_Solution1(5)) 103 | XCTAssertEqual(6, solution.getUglyNumber_Solution1(6)) 104 | XCTAssertEqual(8, solution.getUglyNumber_Solution1(7)) 105 | XCTAssertEqual(9, solution.getUglyNumber_Solution1(8)) 106 | XCTAssertEqual(10, solution.getUglyNumber_Solution1(9)) 107 | XCTAssertEqual(12, solution.getUglyNumber_Solution1(10)) 108 | XCTAssertEqual(15, solution.getUglyNumber_Solution1(11)) 109 | //XCTAssertEqual(859963392, solution.getUglyNumber_Solution1(1500)) //太tm耗时了 110 | } 111 | func testCase2() { 112 | XCTAssertEqual(1, solution.getUglyNumber_Solution2(1)) 113 | XCTAssertEqual(2, solution.getUglyNumber_Solution2(2)) 114 | XCTAssertEqual(3, solution.getUglyNumber_Solution2(3)) 115 | XCTAssertEqual(4, solution.getUglyNumber_Solution2(4)) 116 | XCTAssertEqual(5, solution.getUglyNumber_Solution2(5)) 117 | XCTAssertEqual(6, solution.getUglyNumber_Solution2(6)) 118 | XCTAssertEqual(8, solution.getUglyNumber_Solution2(7)) 119 | XCTAssertEqual(9, solution.getUglyNumber_Solution2(8)) 120 | XCTAssertEqual(10, solution.getUglyNumber_Solution2(9)) 121 | XCTAssertEqual(12, solution.getUglyNumber_Solution2(10)) 122 | XCTAssertEqual(15, solution.getUglyNumber_Solution2(11)) 123 | XCTAssertEqual(859963392, solution.getUglyNumber_Solution2(1500)) 124 | } 125 | } 126 | 127 | UnitTests.defaultTestSuite.run() 128 | -------------------------------------------------------------------------------- /49_UglyNumber.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /50_01_FirstNotRepeatingChar.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | //================================================================== 2 | // 《剑指Offer——名企面试官精讲典型编程题》代码 3 | //================================================================== 4 | // 面试题50(一):字符串中第一个只出现一次的字符 5 | // 题目:在字符串中找出第一个只出现一次的字符。如输入"abaccdeff",则输出 6 | // 'b'。 7 | 8 | import Foundation 9 | import XCTest 10 | 11 | class Solution { 12 | 13 | /** 14 | 查找字符串中第一个只出现一次的字符 15 | - Parameters: 16 | - string: 输入的字符串 17 | - Returns: 第一个不重复的字符 18 | 解法:利用字典存储各个字符的出现次数 19 | */ 20 | func getFirstNotRepeatingChar(_ string: String) -> Character? { 21 | let chars = Array(string) 22 | var dict = [Character:Int]() 23 | for char in chars { 24 | if dict[char] == nil { 25 | dict[char] = 1 26 | } else { 27 | dict[char]! += 1 28 | } 29 | } 30 | for char in chars { 31 | if dict[char]! == 1 { 32 | return char 33 | } 34 | } 35 | return nil 36 | } 37 | } 38 | 39 | class UnitTests: XCTestCase { 40 | var solution: Solution! 41 | 42 | override func setUp() { 43 | super.setUp() 44 | solution = Solution() 45 | } 46 | func testCase1() { 47 | XCTAssertEqual("l", solution.getFirstNotRepeatingChar("google")) 48 | } 49 | func testCase2() { 50 | XCTAssertEqual(nil, solution.getFirstNotRepeatingChar("aabccdbd")) 51 | } 52 | func testCase3() { 53 | XCTAssertEqual("a", solution.getFirstNotRepeatingChar("abcdefg")) 54 | } 55 | } 56 | 57 | UnitTests.defaultTestSuite.run() 58 | -------------------------------------------------------------------------------- /50_01_FirstNotRepeatingChar.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /50_02_FirstCharacterInStream.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | //================================================================== 2 | // 《剑指Offer——名企面试官精讲典型编程题》代码 3 | //================================================================== 4 | // 面试题50(二):字符流中第一个只出现一次的字符 5 | // 题目:请实现一个函数用来找出字符流中第一个只出现一次的字符。例如,当从 6 | // 字符流中只读出前两个字符"go"时,第一个只出现一次的字符是'g'。当从该字 7 | // 符流中读出前六个字符"google"时,第一个只出现一次的字符是'l'。 8 | 9 | import Foundation 10 | import XCTest 11 | 12 | class Solution { 13 | 14 | /** 15 | 返回第一个不重复的字符 16 | - Returns: 第一个不重复的字符 17 | 解法:利用字典存储各个字符的出现次数 18 | */ 19 | func getFirstNotRepeatingChar() -> Character? { 20 | return dict.filter{ $0.value>=0 }.min {a, b in a.value < b.value }?.key 21 | } 22 | private var dict = [Character: Int]() 23 | private var index = 0 24 | func insert(_ char: Character) { 25 | if dict[char] == nil { 26 | dict[char] = index //存储对应的位置 27 | } else { 28 | dict[char] = -1 //标记该char已经出现重复情况 29 | } 30 | index += 1 31 | } 32 | } 33 | 34 | class UnitTests: XCTestCase { 35 | var solution: Solution! 36 | 37 | override func setUp() { 38 | super.setUp() 39 | solution = Solution() 40 | } 41 | func testCase1() { 42 | //g , 第一个只出现一次的字符是 g 43 | solution.insert("g") 44 | XCTAssertEqual("g", solution.getFirstNotRepeatingChar()) 45 | //go , 第一个只出现一次的字符是 g 46 | solution.insert("o") 47 | XCTAssertEqual("g", solution.getFirstNotRepeatingChar()) 48 | //goo , 第一个只出现一次的字符是 g 49 | solution.insert("o") 50 | XCTAssertEqual("g", solution.getFirstNotRepeatingChar()) 51 | //goog , 第一个只出现一次的字符是 nil(两个字符都重复了) 52 | solution.insert("g") 53 | XCTAssertEqual(nil, solution.getFirstNotRepeatingChar()) 54 | //googl , 第一个只出现一次的字符是 l 55 | solution.insert("l") 56 | XCTAssertEqual("l", solution.getFirstNotRepeatingChar()) 57 | //google , 第一个只出现一次的字符是 l 58 | solution.insert("e") 59 | XCTAssertEqual("l", solution.getFirstNotRepeatingChar()) 60 | } 61 | } 62 | 63 | UnitTests.defaultTestSuite.run() 64 | -------------------------------------------------------------------------------- /50_02_FirstCharacterInStream.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /51_InversePairs.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | //================================================================== 2 | // 《剑指Offer——名企面试官精讲典型编程题》代码 3 | //================================================================== 4 | // 面试题51:数组中的逆序对 5 | // 题目:在数组中的两个数字如果前面一个数字大于后面的数字,则这两个数字组 6 | // 成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。 7 | 8 | import Foundation 9 | import XCTest 10 | 11 | class Solution { 12 | 13 | /** 14 | 求数组中的逆序对 15 | - Parameters: 16 | - data: 输入的数组 17 | - Returns: pairCount:逆序对的个数 merged 合并后的数组 18 | 解法:利用归并排序算法,left 和 right 部分分别从尾到头进行合并,如果当前合并 left > right,则逆序对的数量记上 right 部分未合并项的数量 19 | */ 20 | func InversePairs(_ data: [T]) -> (pairCount:Int, merged:[T]) { 21 | guard data.count > 1 else { return (0, data) } 22 | let mid = data.count / 2 23 | let leftResult = InversePairs(Array(data[0..(_ leftPile: [T], _ rightPile:[T]) -> (pairCount:Int, merged:[T]) { 36 | var leftIndex = leftPile.endIndex - 1 37 | var rightIndex = rightPile.endIndex - 1 38 | var orderedPile:[T] = [] 39 | var count = 0 40 | if orderedPile.capacity < leftPile.count + rightPile.count { 41 | orderedPile.reserveCapacity(leftPile.count + rightPile.count) 42 | } 43 | while true { 44 | guard leftIndex >= 0 else { 45 | for i in stride(from: rightIndex, through: 0, by: -1) { 46 | orderedPile.insert(rightPile[i], at: 0) 47 | } 48 | break 49 | } 50 | guard rightIndex >= 0 else { 51 | for i in stride(from: leftIndex, through: 0, by: -1) { 52 | orderedPile.insert(leftPile[i], at: 0) 53 | } 54 | break 55 | } 56 | if leftPile[leftIndex] > rightPile[rightIndex] { 57 | orderedPile.insert(leftPile[leftIndex], at: 0) 58 | leftIndex -= 1 59 | count = count + rightIndex + 1 60 | } else { 61 | orderedPile.insert(rightPile[rightIndex], at: 0) 62 | rightIndex -= 1 63 | } 64 | } 65 | return (count, orderedPile) 66 | } 67 | } 68 | 69 | class UnitTests: XCTestCase { 70 | var solution: Solution! 71 | 72 | override func setUp() { 73 | super.setUp() 74 | solution = Solution() 75 | } 76 | func testCase1() { 77 | let data = [1,2,3,4,7,6,5] 78 | XCTAssertEqual(3, solution.InversePairs(data).pairCount) 79 | } 80 | func testCase2() { 81 | let data = [6,5,4,3,2,1] 82 | XCTAssertEqual(15, solution.InversePairs(data).pairCount) 83 | } 84 | func testCase3() { 85 | let data = [1,2,3,4,5,6] 86 | XCTAssertEqual(0, solution.InversePairs(data).pairCount) 87 | } 88 | func testCase4() { 89 | let data = [1] 90 | XCTAssertEqual(0, solution.InversePairs(data).pairCount) 91 | } 92 | func testCase5() { 93 | let data = [1,2] 94 | XCTAssertEqual(0, solution.InversePairs(data).pairCount) 95 | } 96 | func testCase6() { 97 | let data = [2,1] 98 | XCTAssertEqual(1, solution.InversePairs(data).pairCount) 99 | } 100 | func testCase7() { 101 | let data = [1,2,1,2,1] 102 | XCTAssertEqual(3, solution.InversePairs(data).pairCount) 103 | } 104 | } 105 | 106 | UnitTests.defaultTestSuite.run() 107 | -------------------------------------------------------------------------------- /51_InversePairs.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /52_FirstCommonNodesInLists.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | //================================================================== 2 | // 《剑指Offer——名企面试官精讲典型编程题》代码 3 | //================================================================== 4 | // 面试题52:两个链表的第一个公共结点 5 | // 题目:输入两个链表,找出它们的第一个公共结点。 6 | 7 | import Foundation 8 | import XCTest 9 | 10 | class Solution { 11 | /** 12 | 查找两个链表的第一个公共节点 13 | - Parameters: 14 | - node1: 链表1 15 | - node2: 链表2 16 | - Returns: 第一个公共节点 17 | 解法:分别求两链表的长度计算出长度差d, 18 | 让长链表先走d个节点, 然后跟短链表一起遍历每个节点,相同的那个节点便是公共节点 19 | */ 20 | func FindFirstCommonNode(_ node1: ListNode?, _ node2: ListNode?) -> ListNode? { 21 | let node1Length = GetListLength(node1) 22 | let node2Length = GetListLength(node2) 23 | var headLong:ListNode? = node1Length > node2Length ? node1 : node2 24 | var headShort:ListNode? = node1Length > node2Length ? node2 : node1 25 | var diff = abs(node1Length - node2Length) 26 | while diff > 0 { 27 | headLong = headLong!.next 28 | diff -= 1 29 | } 30 | while headLong != nil && headShort != nil && headLong != headShort { 31 | headLong = headLong?.next 32 | headShort = headShort?.next 33 | } 34 | return headLong 35 | } 36 | /** 37 | 获取链表的长度 38 | - Parameters: 39 | - node: 链表头 40 | - Returns: 长度 41 | 解法: 42 | */ 43 | private func GetListLength(_ node: ListNode?) -> Int { 44 | var count = 0 45 | var head = node 46 | while head != nil { 47 | count += 1 48 | head = head!.next 49 | } 50 | return count 51 | } 52 | } 53 | 54 | class UnitTests: XCTestCase { 55 | var solution: Solution! 56 | 57 | override func setUp() { 58 | super.setUp() 59 | solution = Solution() 60 | } 61 | // 第一个公共结点在链表中间 62 | // 1 - 2 - 3 \ 63 | // 6 - 7 64 | // 4 - 5 / 65 | func testCase1() { 66 | let node7 = ListNode(value: 7, next: nil) 67 | let node6 = ListNode(value: 6, next: node7) 68 | let node5 = ListNode(value: 5, next: node6) 69 | let node4 = ListNode(value: 4, next: node5) 70 | let node3 = ListNode(value: 3, next: node6) 71 | let node2 = ListNode(value: 2, next: node3) 72 | let node1 = ListNode(value: 1, next: node2) 73 | XCTAssertEqual(6, solution.FindFirstCommonNode(node1, node4)?.value) 74 | } 75 | 76 | // 没有公共节点 77 | // 1 - 2 - 3 - 4 78 | // 79 | // 5 - 6 - 7 80 | func testCase2() { 81 | let node7 = ListNode(value: 7, next: nil) 82 | let node6 = ListNode(value: 6, next: node7) 83 | let node5 = ListNode(value: 5, next: node6) 84 | let node4 = ListNode(value: 4, next: nil) 85 | let node3 = ListNode(value: 3, next: node4) 86 | let node2 = ListNode(value: 2, next: node3) 87 | let node1 = ListNode(value: 1, next: node2) 88 | XCTAssertEqual(nil, solution.FindFirstCommonNode(node1, node5)?.value) 89 | } 90 | 91 | // 公共结点是最后一个结点 92 | // 1 - 2 - 3 - 4 \ 93 | // 7 94 | // 5 - 6 / 95 | func testCase3() { 96 | let node7 = ListNode(value: 7, next: nil) 97 | let node6 = ListNode(value: 6, next: node7) 98 | let node5 = ListNode(value: 5, next: node6) 99 | let node4 = ListNode(value: 4, next: node7) 100 | let node3 = ListNode(value: 3, next: node4) 101 | let node2 = ListNode(value: 2, next: node3) 102 | let node1 = ListNode(value: 1, next: node2) 103 | XCTAssertEqual(7, solution.FindFirstCommonNode(node1, node5)?.value) 104 | } 105 | // 公共结点是第一个结点 106 | // 1 - 2 - 3 - 4 - 5 107 | // 两个链表完全重合 108 | func testCase4() { 109 | let node5 = ListNode(value: 5, next: nil) 110 | let node4 = ListNode(value: 4, next: node5) 111 | let node3 = ListNode(value: 3, next: node4) 112 | let node2 = ListNode(value: 2, next: node3) 113 | let node1 = ListNode(value: 1, next: node2) 114 | XCTAssertEqual(1, solution.FindFirstCommonNode(node1, node1)?.value) 115 | } 116 | 117 | // 输入的两个链表有一个空链表 118 | func testCase5() { 119 | let node5 = ListNode(value: 5, next: nil) 120 | let node4 = ListNode(value: 4, next: node5) 121 | let node3 = ListNode(value: 3, next: node4) 122 | let node2 = ListNode(value: 2, next: node3) 123 | let node1 = ListNode(value: 1, next: node2) 124 | XCTAssertEqual(nil, solution.FindFirstCommonNode(node1, nil)?.value) 125 | } 126 | } 127 | 128 | UnitTests.defaultTestSuite.run() 129 | -------------------------------------------------------------------------------- /52_FirstCommonNodesInLists.playground/Sources/ListNode.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public class ListNode: Equatable { 4 | public var next: ListNode? 5 | public var value: Int 6 | 7 | public init(value: Int, next: ListNode?) { 8 | self.value = value 9 | self.next = next 10 | } 11 | 12 | public static func ==(left: ListNode, right: ListNode) -> Bool { 13 | return left.value == right.value 14 | } 15 | 16 | } 17 | 18 | -------------------------------------------------------------------------------- /52_FirstCommonNodesInLists.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /53_01_NumberOfK.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | //================================================================== 2 | // 《剑指Offer——名企面试官精讲典型编程题》代码 3 | //================================================================== 4 | // 面试题53(一):数字在排序数组中出现的次数 5 | // 题目:统计一个数字在排序数组中出现的次数。例如输入排序数组{1, 2, 3, 3, 6 | // 3, 3, 4, 5}和数字3,由于3在这个数组中出现了4次,因此输出4。 7 | 8 | import Foundation 9 | import XCTest 10 | 11 | class Solution { 12 | /** 13 | 统计数字在排序数组中出现的次数 14 | - Parameters: 15 | - data: 排序数组 16 | - k:查找的数字 17 | - Returns: 在数组中出现的次数 18 | 解法:利用二分法分别查找连续出现数字的第一个和最后一个位置,根据两个位置可得出出现次数 19 | */ 20 | func GetNumberOfK(in data: [Int], k:Int) -> Int { 21 | guard data.count > 0 else { 22 | return 0 23 | } 24 | let first = GetFirstK(in: data, k: k, from: 0, to: data.endIndex - 1) 25 | let last = GetLastK(in: data, k: k, from: 0, to: data.endIndex - 1) 26 | if first > -1 && last > -1 { 27 | return last - first + 1 28 | } 29 | return 0 30 | } 31 | /** 32 | 查找排序数组[startIndex,endIndex]范围内第一次出现数字k的位置 33 | - Parameters: 34 | - data: 排序数组 35 | - k:查找的数字 36 | - startIndex:开始查找的位置 37 | - endIndex: 结束查找的位置 38 | - Returns: 在数组中第一次出现的位置(没有返回-1) 39 | */ 40 | private func GetFirstK(in data: [Int], k: Int, from startIndex: Int, to endIndex: Int) -> Int { 41 | var startIndex = startIndex, endIndex = endIndex 42 | guard endIndex >= startIndex else { 43 | return -1 44 | } 45 | let mid = (startIndex + endIndex) / 2 46 | 47 | if data[mid] == k { 48 | if (mid > 0 && data[mid-1] != k) { 49 | return mid 50 | } else if mid == 0 { 51 | return mid 52 | } else { 53 | endIndex = mid - 1 54 | } 55 | } else if data[mid] > k { 56 | endIndex = mid - 1 57 | } else { 58 | startIndex = mid + 1 59 | } 60 | return GetFirstK(in: data, k: k, from: startIndex, to: endIndex) 61 | } 62 | /** 63 | 查找排序数组[startIndex,endIndex]范围内最后一次出现数字k的位置 64 | - Parameters: 65 | - data: 排序数组 66 | - k:查找的数字 67 | - startIndex:开始查找的位置 68 | - endIndex: 结束查找的位置 69 | - Returns: 在数组中最后一次出现的位置(没有返回-1) 70 | */ 71 | private func GetLastK(in data: [Int], k: Int, from startIndex: Int, to endIndex: Int) -> Int { 72 | var startIndex = startIndex, endIndex = endIndex 73 | guard endIndex >= startIndex else { 74 | return -1 75 | } 76 | let mid = (startIndex + endIndex) / 2 77 | if data[mid] == k { 78 | if mid == data.endIndex - 1 { 79 | return mid 80 | } else if (mid > 0 && data[mid+1] != k) { 81 | return mid 82 | } else { 83 | startIndex = mid + 1 84 | } 85 | } else if data[mid] < k { 86 | startIndex = mid + 1 87 | } else { 88 | endIndex = mid - 1 89 | } 90 | return GetLastK(in: data, k: k, from: startIndex, to: endIndex) 91 | } 92 | } 93 | 94 | class UnitTests: XCTestCase { 95 | var solution: Solution! 96 | 97 | override func setUp() { 98 | super.setUp() 99 | solution = Solution() 100 | } 101 | // 查找的数字出现在数组的中间 102 | func testCase1() { 103 | let data = [1,2,3,3,3,3,4,5] 104 | XCTAssertEqual(4, solution.GetNumberOfK(in: data, k: 3)) 105 | } 106 | // 查找的数字出现在数组的开头 107 | func testCase2() { 108 | let data = [3,3,3,3,4,5] 109 | XCTAssertEqual(4, solution.GetNumberOfK(in: data, k: 3)) 110 | } 111 | // 查找的数字出现在数组的结尾 112 | func testCase3() { 113 | let data = [1,2,3,3,3,3] 114 | XCTAssertEqual(4, solution.GetNumberOfK(in: data, k: 3)) 115 | } 116 | // 查找的数字不存在 117 | func testCase4() { 118 | let data = [1,3,3,3,3,4,5] 119 | XCTAssertEqual(0, solution.GetNumberOfK(in: data, k: 2)) 120 | } 121 | // 查找的数字比第一个数字还小,不存在 122 | func testCase5() { 123 | let data = [1,2,3,3,3,3,4,5] 124 | XCTAssertEqual(0, solution.GetNumberOfK(in: data, k: 0)) 125 | } 126 | // 查找的数字比最后一个数字还大,不存在 127 | func testCase6() { 128 | let data = [1,2,3,3,3,3,4,5] 129 | XCTAssertEqual(0, solution.GetNumberOfK(in: data, k: 6)) 130 | } 131 | // 数组中的数字从头到尾都是查找的数字 132 | func testCase7() { 133 | let data = [3,3,3,3] 134 | XCTAssertEqual(4, solution.GetNumberOfK(in: data, k: 3)) 135 | } 136 | // 数组中的数字从头到尾只有一个重复的数字,不是查找的数字 137 | func testCase8() { 138 | let data = [3,3,3,3] 139 | XCTAssertEqual(0, solution.GetNumberOfK(in: data, k: 4)) 140 | } 141 | // 数组中只有一个数字,是查找的数字 142 | func testCase9() { 143 | let data = [3] 144 | XCTAssertEqual(1, solution.GetNumberOfK(in: data, k: 3)) 145 | } 146 | // 数组中只有一个数字,不是查找的数字 147 | func testCase10() { 148 | let data = [3] 149 | XCTAssertEqual(0, solution.GetNumberOfK(in: data, k: 4)) 150 | } 151 | 152 | } 153 | 154 | UnitTests.defaultTestSuite.run() 155 | -------------------------------------------------------------------------------- /53_01_NumberOfK.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /53_02_MissingNumber.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | //================================================================== 2 | // 《剑指Offer——名企面试官精讲典型编程题》代码 3 | //================================================================== 4 | // 面试题53(二):0到n-1中缺失的数字 5 | // 题目:一个长度为n-1的递增排序数组中的所有数字都是唯一的,并且每个数字 6 | // 都在范围0到n-1之内。在范围0到n-1的n个数字中有且只有一个数字不在该数组 7 | // 中,请找出这个数字。 8 | 9 | import Foundation 10 | import XCTest 11 | 12 | class Solution { 13 | /** 14 | 查找递增排序数组中缺失的那个数字 15 | - Parameters: 16 | - data: 递增数组 17 | - Returns: 缺失那个数字 18 | 解法:利用二分法查找,如果index和数据项相同,说明在右边部分,否则在左边部分 19 | */ 20 | func GetMissingNumber(in data: [Int]) -> Int? { 21 | guard data.count > 0 else { 22 | return nil 23 | } 24 | var start = 0 25 | var end = data.endIndex - 1 26 | while start <= end { 27 | let mid = (start + end) / 2 28 | if data[mid] != mid { 29 | if mid == 0 || data[mid - 1] == mid - 1 { 30 | //说明 mid 就是缺失的那个数 31 | return mid 32 | } 33 | end = mid - 1 //往左半部分继续找 34 | } else { 35 | //data[mid] == mid 说明左边没有缺失,往右半部分继续找 36 | start = mid + 1 37 | } 38 | } 39 | if start == data.count { 40 | //查找到最后一个了,说明缺失的是最后一个 41 | return data.count 42 | } 43 | return nil 44 | } 45 | } 46 | 47 | class UnitTests: XCTestCase { 48 | var solution: Solution! 49 | 50 | override func setUp() { 51 | super.setUp() 52 | solution = Solution() 53 | } 54 | 55 | //缺失第一个数字0 56 | func testCase1() { 57 | let data = [1,2,3,4,5] 58 | XCTAssertEqual(0, solution.GetMissingNumber(in: data)) 59 | } 60 | //缺失最后一个数字5 61 | func testCase2() { 62 | let data = [0,1,2,3,4] 63 | XCTAssertEqual(5, solution.GetMissingNumber(in: data)) 64 | } 65 | //缺失中间的数字3 66 | func testCase3() { 67 | let data = [0,1,2,4,5] 68 | XCTAssertEqual(3, solution.GetMissingNumber(in: data)) 69 | } 70 | //数组只有一个数字,缺失0 71 | func testCase4() { 72 | let data = [1] 73 | XCTAssertEqual(0, solution.GetMissingNumber(in: data)) 74 | } 75 | //数组只有一个数字,缺失1 76 | func testCase5() { 77 | let data = [0] 78 | XCTAssertEqual(1, solution.GetMissingNumber(in: data)) 79 | } 80 | //空数组 81 | func testCase6() { 82 | let data:[Int] = [] 83 | XCTAssertEqual(nil, solution.GetMissingNumber(in: data)) 84 | } 85 | } 86 | 87 | UnitTests.defaultTestSuite.run() 88 | -------------------------------------------------------------------------------- /53_02_MissingNumber.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /53_03_IntegerIdenticalToIndex.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | //================================================================== 2 | // 《剑指Offer——名企面试官精讲典型编程题》代码 3 | //================================================================== 4 | // 面试题53(三):数组中数值和下标相等的元素 5 | // 题目:假设一个单调递增的数组里的每个元素都是整数并且是唯一的。请编程实 6 | // 现一个函数找出数组中任意一个数值等于其下标的元素。例如,在数组{-3, -1, 7 | // 1, 3, 5}中,数字3和它的下标相等。 8 | 9 | import Foundation 10 | import XCTest 11 | 12 | class Solution { 13 | /** 14 | 查找数组中数值和下标相等的元素 15 | - Parameters: 16 | - data: 递增数组 17 | - Returns: 数值与下标相等的元素 18 | 解法:二分法,如果当前下标的元素值比下标大,则右边部分元素的值都比各自的下标大,继续查找左边。 19 | */ 20 | func GetNumberSameAsIndex(in data: [Int]) -> Int? { 21 | guard data.count > 0 else { 22 | return nil 23 | } 24 | var start = 0 25 | var end = data.count - 1 26 | while start <= end { 27 | let mid = (start + end) / 2 28 | if data[mid] == mid { 29 | return mid 30 | } 31 | if data[mid] > mid { 32 | end = mid - 1 33 | } else { 34 | start = mid + 1 35 | } 36 | } 37 | return nil 38 | } 39 | } 40 | 41 | class UnitTests: XCTestCase { 42 | var solution: Solution! 43 | 44 | override func setUp() { 45 | super.setUp() 46 | solution = Solution() 47 | } 48 | func testCase1() { 49 | let data = [-3,-1,1,3,5] 50 | XCTAssertEqual(3, solution.GetNumberSameAsIndex(in: data)) 51 | } 52 | func testCase2() { 53 | let data = [0,1,3,5,6] 54 | XCTAssertEqual(0, solution.GetNumberSameAsIndex(in: data)) 55 | } 56 | func testCase3() { 57 | let data = [-1,0,1,2,4] 58 | XCTAssertEqual(4, solution.GetNumberSameAsIndex(in: data)) 59 | } 60 | func testCase4() { 61 | let data = [-1,0,1,2,5] 62 | XCTAssertEqual(nil, solution.GetNumberSameAsIndex(in: data)) 63 | } 64 | func testCase5() { 65 | let data = [0] 66 | XCTAssertEqual(0, solution.GetNumberSameAsIndex(in: data)) 67 | } 68 | func testCase6() { 69 | let data = [10] 70 | XCTAssertEqual(nil, solution.GetNumberSameAsIndex(in: data)) 71 | } 72 | func testCase7() { 73 | let data:[Int] = [] 74 | XCTAssertEqual(nil, solution.GetNumberSameAsIndex(in: data)) 75 | } 76 | 77 | } 78 | 79 | UnitTests.defaultTestSuite.run() 80 | -------------------------------------------------------------------------------- /53_03_IntegerIdenticalToIndex.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /54_KthNodeInBST.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /55_01_TreeDepth.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | //================================================================== 2 | // 《剑指Offer——名企面试官精讲典型编程题》代码 3 | //================================================================== 4 | // 面试题55(一):二叉树的深度 5 | // 题目:输入一棵二叉树的根结点,求该树的深度。从根结点到叶结点依次经过的 6 | // 结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度。 7 | 8 | import Foundation 9 | import XCTest 10 | 11 | class BinaryTreeNode: Equatable { 12 | var left: BinaryTreeNode? 13 | var right: BinaryTreeNode? 14 | var value: Int 15 | 16 | init(value: Int, left: BinaryTreeNode?, right: BinaryTreeNode?) { 17 | self.value = value 18 | self.left = left 19 | self.right = right 20 | } 21 | static func ==(left: BinaryTreeNode, right: BinaryTreeNode) -> Bool { 22 | return left.value == right.value 23 | } 24 | } 25 | 26 | class Solution { 27 | 28 | /** 29 | 返回二叉树的深度 30 | - Parameters: 31 | - root: 二叉树根节点 32 | - Returns: 深度 33 | 解法:利用递归,比较左右子树的深度,取较大者 34 | */ 35 | func TreeDepth(_ node: BinaryTreeNode?) -> Int { 36 | guard node != nil else { 37 | return 0 38 | } 39 | let leftTreeDepth = TreeDepth(node?.left) 40 | let rightTreeDepth = TreeDepth(node?.right) 41 | return leftTreeDepth > rightTreeDepth ? leftTreeDepth + 1 : rightTreeDepth + 1 42 | } 43 | } 44 | 45 | class UnitTests: XCTestCase { 46 | var solution: Solution! 47 | 48 | override func setUp() { 49 | super.setUp() 50 | solution = Solution() 51 | } 52 | // 1 53 | // / \ 54 | // 2 3 55 | // /\ \ 56 | // 4 5 6 57 | // / 58 | // 7 59 | func testCase1() { 60 | let node7 = BinaryTreeNode(value: 7, left: nil, right: nil) 61 | let node6 = BinaryTreeNode(value: 6, left: nil, right: nil) 62 | let node5 = BinaryTreeNode(value: 5, left: node7, right: nil) 63 | let node4 = BinaryTreeNode(value: 4, left: nil, right: nil) 64 | let node3 = BinaryTreeNode(value: 3, left: nil, right: node6) 65 | let node2 = BinaryTreeNode(value: 2, left: node4, right: node5) 66 | let node1 = BinaryTreeNode(value: 1, left: node2, right: node3) 67 | XCTAssertEqual(4, solution.TreeDepth(node1)) 68 | } 69 | 70 | // 1 71 | // / 72 | // 2 73 | // / 74 | // 3 75 | // / 76 | // 4 77 | // / 78 | // 5 79 | func testCase2() { 80 | let node5 = BinaryTreeNode(value: 5, left: nil, right: nil) 81 | let node4 = BinaryTreeNode(value: 4, left: node5, right: nil) 82 | let node3 = BinaryTreeNode(value: 3, left: node4, right: nil) 83 | let node2 = BinaryTreeNode(value: 2, left: node3, right: nil) 84 | let node1 = BinaryTreeNode(value: 1, left: node2, right: nil) 85 | XCTAssertEqual(5, solution.TreeDepth(node1)) 86 | } 87 | // 1 88 | // \ 89 | // 2 90 | // \ 91 | // 3 92 | // \ 93 | // 4 94 | // \ 95 | // 5 96 | func testCase3() { 97 | let node5 = BinaryTreeNode(value: 5, left: nil, right: nil) 98 | let node4 = BinaryTreeNode(value: 4, left: nil, right: node5) 99 | let node3 = BinaryTreeNode(value: 3, left: nil, right: node4) 100 | let node2 = BinaryTreeNode(value: 2, left: nil, right: node3) 101 | let node1 = BinaryTreeNode(value: 1, left: nil, right: node2) 102 | XCTAssertEqual(5, solution.TreeDepth(node1)) 103 | } 104 | // 树中只有1个结点 105 | func testCase4() { 106 | let node1 = BinaryTreeNode(value: 1, left: nil, right: nil) 107 | XCTAssertEqual(1, solution.TreeDepth(node1)) 108 | } 109 | // 树中没有结点 110 | func testCase5() { 111 | XCTAssertEqual(0, solution.TreeDepth(nil)) 112 | } 113 | } 114 | 115 | UnitTests.defaultTestSuite.run() 116 | -------------------------------------------------------------------------------- /55_01_TreeDepth.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /55_02_BalancedBinaryTree.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /56_01_NumbersAppearOnce.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | //================================================================== 2 | // 《剑指Offer——名企面试官精讲典型编程题》代码 3 | //================================================================== 4 | // 面试题56(一):数组中只出现一次的两个数字 5 | // 题目:一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序 6 | // 找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。 7 | 8 | import Foundation 9 | import XCTest 10 | 11 | class Solution { 12 | 13 | /** 14 | 返回数组中只出现一次的两个数字(其他数字都出现了两次) 15 | - Parameters: 16 | - nums: 数组 17 | - Returns: 两个数字 18 | */ 19 | func FindNumsAppearOnce(_ nums: [Int]) -> (num1: Int?, num2: Int?) { 20 | guard nums.count >= 2 else { 21 | return (nil, nil) 22 | } 23 | let xorResult = nums.reduce(0) { 24 | return $0 ^ $1 25 | } 26 | let indexOf1 = FindFirstBitIs1(xorResult) 27 | var num1 = 0, num2 = 0 28 | nums.forEach { 29 | if(IsBit1($0, at: indexOf1)) { 30 | num1 ^= $0 31 | } else { 32 | num2 ^= $0 33 | } 34 | } 35 | return (min(num1, num2), max(num1, num2)) 36 | } 37 | /** 38 | 查找从右边数起第一个是1的位 39 | - Parameters: 40 | - num: 数字 41 | - index: 第index位(从右开始) 42 | - Returns: 判断结果 43 | */ 44 | private func FindFirstBitIs1(_ num: Int) -> Int{ 45 | var index = 0 46 | var num = num 47 | while num & 1 == 0 && index < num.bitWidth { 48 | num = num >> 1 49 | index += 1 50 | } 51 | return index 52 | } 53 | /** 54 | 判断数字的第index位是不是1 55 | - Parameters: 56 | - num: 数字 57 | - index: 第index位(从右开始) 58 | - Returns: 判断结果 59 | */ 60 | private func IsBit1(_ num: Int, at index:Int) -> Bool { 61 | let num = num >> index 62 | return num & 1 == 1 63 | } 64 | } 65 | 66 | class UnitTests: XCTestCase { 67 | var solution: Solution! 68 | 69 | override func setUp() { 70 | super.setUp() 71 | solution = Solution() 72 | } 73 | 74 | func testCase1() { 75 | let nums = [2,4,3,6,3,2,5,5] 76 | XCTAssertEqual(4, solution.FindNumsAppearOnce(nums).num1) 77 | XCTAssertEqual(6, solution.FindNumsAppearOnce(nums).num2) 78 | } 79 | 80 | func testCase2() { 81 | let nums = [4,6] 82 | XCTAssertEqual(4, solution.FindNumsAppearOnce(nums).num1) 83 | XCTAssertEqual(6, solution.FindNumsAppearOnce(nums).num2) 84 | } 85 | 86 | func testCase3() { 87 | let nums = [4,6,1,1,1,1] 88 | XCTAssertEqual(4, solution.FindNumsAppearOnce(nums).num1) 89 | XCTAssertEqual(6, solution.FindNumsAppearOnce(nums).num2) 90 | } 91 | } 92 | 93 | UnitTests.defaultTestSuite.run() 94 | -------------------------------------------------------------------------------- /56_01_NumbersAppearOnce.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /56_02_NumberAppearingOnce.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | //================================================================== 2 | // 《剑指Offer——名企面试官精讲典型编程题》代码 3 | //================================================================== 4 | // 面试题56(二):数组中唯一只出现一次的数字 5 | // 题目:在一个数组中除了一个数字只出现一次之外,其他数字都出现了三次。请 6 | // 找出那个出现一次的数字。 7 | 8 | import Foundation 9 | import XCTest 10 | 11 | class Solution { 12 | 13 | /** 14 | 返回数组中只出现一次的数字 15 | - Parameters: 16 | - nums: 数组 17 | - Returns: 出现一次的数字 18 | */ 19 | func FindNumberAppearingOnce(_ nums: [Int]) -> Int? { 20 | guard nums.count > 0 else { 21 | return nil 22 | } 23 | var bitSum = Array.init(repeating: 0, count: Int.bitWidth) 24 | nums.forEach { 25 | var bitMask = 1 26 | for i in 0.. 2 | 3 | 4 | -------------------------------------------------------------------------------- /57_01_TwoNumbersWithSum.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | //================================================================== 2 | // 《剑指Offer——名企面试官精讲典型编程题》代码 3 | //================================================================== 4 | // 面试题57(一):和为s的两个数字 5 | // 题目:输入一个递增排序的数组和一个数字s,在数组中查找两个数,使得它们 6 | // 的和正好是s。如果有多对数字的和等于s,输出任意一对即可。 7 | 8 | import Foundation 9 | import XCTest 10 | 11 | class Solution { 12 | 13 | /** 14 | 返回递增排序数组nums中和为sum的两个数字 15 | - Parameters: 16 | - nums: 数组 17 | - sum: 和 18 | - Returns: 和为sum的两个数字 19 | */ 20 | func FindNumbersWithSum(_ nums: [Int], _ sum: Int) -> (num1: Int?, num2: Int?) { 21 | guard nums.count > 2 else { 22 | return (nil, nil) 23 | } 24 | var start = 0 25 | var end = nums.count - 1 26 | while start < end { 27 | let currentSum = nums[start] + nums[end] 28 | if currentSum == sum { 29 | return (nums[start], nums[end]) 30 | } 31 | else if currentSum > sum { 32 | end = end - 1 33 | } else { 34 | start = start + 1 35 | } 36 | } 37 | return (nil, nil) 38 | } 39 | } 40 | 41 | class UnitTests: XCTestCase { 42 | var solution: Solution! 43 | 44 | override func setUp() { 45 | super.setUp() 46 | solution = Solution() 47 | } 48 | // 存在和为s的两个数字,这两个数字位于数组的中间 49 | func testCase1() { 50 | let nums = [1,2,4,7,11,16] 51 | let result = solution.FindNumbersWithSum(nums, 15) 52 | XCTAssertEqual(4, result.num1) 53 | XCTAssertEqual(11, result.num2) 54 | } 55 | // 存在和为s的两个数字,这两个数字位于数组的两段 56 | func testCase2() { 57 | let nums = [1,2,4,7,11,16] 58 | let result = solution.FindNumbersWithSum(nums, 17) 59 | XCTAssertEqual(1, result.num1) 60 | XCTAssertEqual(16, result.num2) 61 | } 62 | // 不存在和为s的两个数字 63 | func testCase3() { 64 | let nums = [1,2,4,7,11,16] 65 | let result = solution.FindNumbersWithSum(nums, 10) 66 | XCTAssertEqual(nil, result.num1) 67 | XCTAssertEqual(nil, result.num2) 68 | } 69 | } 70 | 71 | UnitTests.defaultTestSuite.run() 72 | -------------------------------------------------------------------------------- /57_01_TwoNumbersWithSum.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /57_02_ContinuousSquenceWithSum.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | //================================================================== 2 | // 《剑指Offer——名企面试官精讲典型编程题》代码 3 | //================================================================== 4 | // 面试题57(二):和为s的连续正数序列 5 | // 题目:输入一个正数s,打印出所有和为s的连续正数序列(至少含有两个数)。 6 | // 例如输入15,由于1+2+3+4+5=4+5+6=7+8=15,所以结果打印出3个连续序列1~5、4~6和7~8。 7 | 8 | 9 | import Foundation 10 | import XCTest 11 | 12 | class Solution { 13 | 14 | /** 15 | 查找和为sum的连续正数序列 16 | - Parameters: 17 | - sum: 和 18 | - Returns: 和为s的连续正数序列 19 | */ 20 | func FindContinuousSequence(_ sum: Int) -> [[Int]] { 21 | var small = 1, big = 2 22 | let middle = (sum + 1) / 2 23 | var currentSum = small + big 24 | var result = [[Int]]() 25 | while small < middle { 26 | if currentSum == sum { 27 | result.append(Array(small...big)) 28 | } 29 | 30 | while currentSum > sum && small < middle { 31 | currentSum -= small 32 | small += 1 33 | 34 | if currentSum == sum { 35 | result.append(Array(small...big)) 36 | } 37 | } 38 | 39 | big += 1 40 | currentSum += big 41 | } 42 | return result 43 | } 44 | } 45 | 46 | class UnitTests: XCTestCase { 47 | var solution: Solution! 48 | 49 | override func setUp() { 50 | super.setUp() 51 | solution = Solution() 52 | } 53 | func testCase1() { 54 | XCTAssertEqual(nil, solution.FindContinuousSequence(1).first) 55 | XCTAssertEqual([1,2], solution.FindContinuousSequence(3).first) 56 | XCTAssertEqual(nil, solution.FindContinuousSequence(4).first) 57 | XCTAssertEqual([[2,3,4],[4,5]], solution.FindContinuousSequence(9)) 58 | XCTAssertEqual([[1, 2, 3, 4, 5], [4, 5, 6], [7, 8]], solution.FindContinuousSequence(15)) 59 | XCTAssertEqual([[9, 10, 11, 12, 13, 14, 15, 16], [18, 19, 20, 21, 22]], solution.FindContinuousSequence(100)) 60 | } 61 | } 62 | 63 | UnitTests.defaultTestSuite.run() 64 | -------------------------------------------------------------------------------- /57_02_ContinuousSquenceWithSum.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /58_01_ReverseWordsInSentence.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | //================================================================== 2 | // 《剑指Offer——名企面试官精讲典型编程题》代码 3 | //================================================================== 4 | // 面试题58(一):翻转单词顺序 5 | // 题目:输入一个英文句子,翻转句子中单词的顺序,但单词内字符的顺序不变。 6 | // 为简单起见,标点符号和普通字母一样处理。例如输入字符串"I am a student. ", 7 | // 则输出"student. a am I"。 8 | 9 | 10 | import Foundation 11 | import XCTest 12 | 13 | class Solution { 14 | 15 | /** 16 | 翻转单词顺序 17 | - Parameters: 18 | - sentence: 翻转前的句子 19 | - Returns: 翻转之后的句子 20 | */ 21 | func ReverseSentence(_ sentence: String) -> String { 22 | var chars:[Character] = Array(sentence) 23 | chars.reverse() 24 | let words = chars.split(separator: " ") 25 | guard words.count > 0 else { 26 | return String(chars) 27 | } 28 | var reversed = words.reduce("") { 29 | $0 + $1.reversed() + " " 30 | } 31 | if reversed.count > 1 { 32 | reversed.removeLast() 33 | } 34 | return reversed 35 | } 36 | } 37 | 38 | class UnitTests: XCTestCase { 39 | var solution: Solution! 40 | 41 | override func setUp() { 42 | super.setUp() 43 | solution = Solution() 44 | } 45 | //多个单词 46 | func testCase1() { 47 | let data = "I am a student." 48 | XCTAssertEqual("student. a am I", solution.ReverseSentence(data)) 49 | } 50 | //emoji 51 | func testCase2() { 52 | let data = "I ❤️ you." 53 | XCTAssertEqual("you. ❤️ I", solution.ReverseSentence(data)) 54 | } 55 | //只有一个单词 56 | func testCase3() { 57 | let data = "Wonderful" 58 | XCTAssertEqual("Wonderful", solution.ReverseSentence(data)) 59 | } 60 | //空字符串 61 | func testCase4() { 62 | let data = "" 63 | XCTAssertEqual("", solution.ReverseSentence(data)) 64 | } 65 | //空格 66 | func testCase5() { 67 | let data = " " 68 | XCTAssertEqual(data, solution.ReverseSentence(data)) 69 | } 70 | } 71 | 72 | UnitTests.defaultTestSuite.run() 73 | -------------------------------------------------------------------------------- /58_01_ReverseWordsInSentence.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /58_02_LeftRotateString.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | //================================================================== 2 | // 《剑指Offer——名企面试官精讲典型编程题》代码 3 | //================================================================== 4 | // 面试题58(二):左旋转字符串 5 | // 题目:字符串的左旋转操作是把字符串前面的若干个字符转移到字符串的尾部。 6 | // 请定义一个函数实现字符串左旋转操作的功能。比如输入字符串"abcdefg"和数 7 | // 字2,该函数将返回左旋转2位得到的结果"cdefgab"。 8 | import Foundation 9 | import XCTest 10 | 11 | class Solution { 12 | 13 | /** 14 | 左旋转字符串 15 | - Parameters: 16 | - content: 字符串 17 | - n: 左旋转的字符个数 18 | - Returns: 左旋转之后的字符串 19 | */ 20 | func LeftRotateString(_ content: String, _ n: Int) -> String { 21 | guard n > 0 && n < content.count else { 22 | return content 23 | } 24 | var content = Array(content) 25 | let left = Array(content[0...n-1]) 26 | var right = Array(content[n...]) 27 | right.append(contentsOf: left) 28 | return String(right) 29 | } 30 | } 31 | 32 | class UnitTests: XCTestCase { 33 | var solution: Solution! 34 | 35 | override func setUp() { 36 | super.setUp() 37 | solution = Solution() 38 | } 39 | func testCase1() { 40 | let data = "abcdefg" 41 | XCTAssertEqual("bcdefga", solution.LeftRotateString(data, 1)) 42 | } 43 | func testCase2() { 44 | let data = "abcdefg" 45 | XCTAssertEqual("cdefgab", solution.LeftRotateString(data, 2)) 46 | } 47 | func testCase4() { 48 | let data = "abcdefg" 49 | XCTAssertEqual("gabcdef", solution.LeftRotateString(data, 6)) 50 | } 51 | func testCase5() { 52 | let data = "abcdefg" 53 | XCTAssertEqual("abcdefg", solution.LeftRotateString(data, 0)) 54 | } 55 | func testCase6() { 56 | let data = "abcdefg" 57 | XCTAssertEqual("abcdefg", solution.LeftRotateString(data, 7)) 58 | } 59 | } 60 | 61 | UnitTests.defaultTestSuite.run() 62 | -------------------------------------------------------------------------------- /58_02_LeftRotateString.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /59_01_MaxInSlidingWindow.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | //================================================================== 2 | // 《剑指Offer——名企面试官精讲典型编程题》代码 3 | //================================================================== 4 | // 面试题59(一):滑动窗口的最大值 5 | // 题目:给定一个数组和滑动窗口的大小,请找出所有滑动窗口里的最大值。例如, 6 | // 如果输入数组{2, 3, 4, 2, 6, 2, 5, 1}及滑动窗口的大小3,那么一共存在6个 7 | // 滑动窗口,它们的最大值分别为{4, 4, 6, 6, 6, 5}, 8 | 9 | 10 | import Foundation 11 | import XCTest 12 | 13 | class Solution { 14 | 15 | /** 16 | 滑动窗口的最大值 17 | - Parameters: 18 | - nums:数组 19 | - size: 滑动窗口大小 20 | - Returns: 所有滑动窗口里的最大值 21 | */ 22 | func maxInWindows(_ nums: [Int], _ size: Int) -> [Int] { 23 | var maxInWindows = [Int]() 24 | var queue = [Int]() 25 | guard nums.count >= size && size > 0 else { 26 | return maxInWindows 27 | } 28 | //将第一个滑动窗口的值添加到队列中 29 | for index in stride(from: 0, to: size, by: 1) { 30 | while queue.count > 0 && nums[index] > nums[queue.last!] { 31 | queue.removeLast() 32 | } 33 | queue.append(index) //这里存储的是数组的下标,因为后续要根据下标来判断是否需要删除窗口之外的数 见① 34 | } 35 | //处理其他滑动窗口 36 | for index in stride(from: size, to: nums.endIndex, by: 1) { 37 | maxInWindows.append(nums[queue.first!]) 38 | while queue.count > 0 && nums[index] > nums[queue.last!] { 39 | queue.removeLast() 40 | } 41 | if queue.count > 0 && queue.first! + size <= index { 42 | //①: 队列头部的最大数已经不在滑动窗口中,需要删除 43 | queue.removeFirst() 44 | } 45 | queue.append(index) 46 | } 47 | maxInWindows.append(nums[queue.first!]) 48 | return maxInWindows 49 | } 50 | } 51 | 52 | class UnitTests: XCTestCase { 53 | var solution: Solution! 54 | 55 | override func setUp() { 56 | super.setUp() 57 | solution = Solution() 58 | } 59 | func testCase1() { 60 | let nums = [2,3,4,2,6,2,5,1] 61 | let expected = [4,4,6,6,6,5] 62 | XCTAssertEqual(expected, solution.maxInWindows(nums, 3)) 63 | } 64 | func testCase2() { 65 | let nums = [1,3,-1,-3,5,3,6,7] 66 | let expected = [3,3,5,5,6,7] 67 | XCTAssertEqual(expected, solution.maxInWindows(nums, 3)) 68 | } 69 | func testCase3() { 70 | let nums = [1, 3, 5, 7, 9, 11, 13, 15] 71 | let expected = [7, 9, 11, 13, 15] 72 | XCTAssertEqual(expected, solution.maxInWindows(nums, 4)) 73 | } 74 | func testCase4() { 75 | let nums = [16, 14, 12, 10, 8, 6, 4] 76 | let expected = [16, 14, 12] 77 | XCTAssertEqual(expected, solution.maxInWindows(nums, 5)) 78 | } 79 | func testCase5() { 80 | let nums = [10,14,12,11] 81 | let expected = [10,14,12,11] 82 | XCTAssertEqual(expected, solution.maxInWindows(nums, 1)) 83 | } 84 | func testCase6() { 85 | let nums = [10,14,12,11] 86 | let expected = [14] 87 | XCTAssertEqual(expected, solution.maxInWindows(nums, 4)) 88 | } 89 | func testCase7() { 90 | let nums = [10,14,12,11] 91 | let expected:[Int] = [] 92 | XCTAssertEqual(expected, solution.maxInWindows(nums, 0)) 93 | } 94 | func testCase8() { 95 | let nums = [10,14,12,11] 96 | let expected:[Int] = [] 97 | XCTAssertEqual(expected, solution.maxInWindows(nums, 5)) 98 | } 99 | func testCase9() { 100 | let nums:[Int] = [] 101 | let expected:[Int] = [] 102 | XCTAssertEqual(expected, solution.maxInWindows(nums, 5)) 103 | } 104 | } 105 | 106 | UnitTests.defaultTestSuite.run() 107 | -------------------------------------------------------------------------------- /59_01_MaxInSlidingWindow.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /59_02_QueueWithMax.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | //================================================================== 2 | // 《剑指Offer——名企面试官精讲典型编程题》代码 3 | //================================================================== 4 | // 面试题59(二):队列的最大值 5 | // 题目:定义一个队列,并实现函数 max 得到队列里的最大值 6 | // 要求函数 max、push、pop的时间复杂度都是 O(1) 7 | 8 | 9 | import Foundation 10 | import XCTest 11 | 12 | class Solution { 13 | private var maximums = [(value: Int, index: Int)]() 14 | private var data = [(value: Int, index: Int)]() 15 | private var currentIndex = 0 16 | /** 17 | 入队 18 | - Parameters: 19 | - nums: 数字 20 | */ 21 | public func push(_ num: Int) { 22 | while maximums.count > 0 && num >= maximums.last!.value { 23 | maximums.removeLast() 24 | } 25 | data.append((num, currentIndex)) 26 | maximums.append((num, currentIndex)) 27 | currentIndex += 1 28 | } 29 | /** 30 | 出队 31 | - Returns: 移除队列的数字 32 | */ 33 | public func pop() -> Int? { 34 | guard data.count > 0 else { 35 | return nil 36 | } 37 | if maximums.first!.index == data.first!.index { 38 | maximums.removeFirst() 39 | } 40 | return data.removeFirst().value 41 | } 42 | /** 43 | 获取当前队列最大值 44 | - Returns: 当前队列d最大值 45 | */ 46 | public func max() -> Int? { 47 | guard maximums.count > 0 else { 48 | return nil 49 | } 50 | return maximums.first!.value 51 | } 52 | } 53 | 54 | class UnitTests: XCTestCase { 55 | var solution: Solution! 56 | 57 | override func setUp() { 58 | super.setUp() 59 | solution = Solution() 60 | } 61 | func testCase1() { 62 | //[2] 63 | solution.push(2) 64 | XCTAssertEqual(2, solution.max()) 65 | 66 | //[2,3] 67 | solution.push(3) 68 | XCTAssertEqual(3, solution.max()) 69 | 70 | //[2,3,4] 71 | solution.push(4) 72 | XCTAssertEqual(4, solution.max()) 73 | 74 | //[2,3,4,2] 75 | solution.push(2) 76 | XCTAssertEqual(4, solution.max()) 77 | 78 | //[3,4,2] 79 | solution.pop() 80 | XCTAssertEqual(4, solution.max()) 81 | 82 | //[4,2] 83 | solution.pop() 84 | XCTAssertEqual(4, solution.max()) 85 | 86 | //[2] 87 | solution.pop() 88 | XCTAssertEqual(2, solution.max()) 89 | 90 | //[2,6] 91 | solution.push(6) 92 | XCTAssertEqual(6, solution.max()) 93 | 94 | //[2,6,2] 95 | solution.push(2) 96 | XCTAssertEqual(6, solution.max()) 97 | 98 | //[2,6,2,5] 99 | solution.push(5) 100 | XCTAssertEqual(6, solution.max()) 101 | 102 | //[6,2,5] 103 | solution.pop() 104 | XCTAssertEqual(6, solution.max()) 105 | 106 | //[2,5] 107 | solution.pop() 108 | XCTAssertEqual(5, solution.max()) 109 | 110 | //[5] 111 | solution.pop() 112 | XCTAssertEqual(5, solution.max()) 113 | 114 | //[5,1] 115 | solution.push(1) 116 | XCTAssertEqual(5, solution.max()) 117 | 118 | } 119 | } 120 | 121 | UnitTests.defaultTestSuite.run() 122 | -------------------------------------------------------------------------------- /59_02_QueueWithMax.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /60_DicesProbability.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | //================================================================== 2 | // 《剑指Offer——名企面试官精讲典型编程题》代码 3 | //================================================================== 4 | // 面试题60:n个骰子的点数 5 | // 题目:把n个骰子扔在地上,所有骰子朝上一面的点数之和为s。输入n,打印出s 6 | // 的所有可能的值出现的概率。 7 | 8 | import Foundation 9 | import XCTest 10 | 11 | class Solution { 12 | let DiceMaxValue: Int = 6 13 | 14 | // 方法一 递归计算出所有可能和的出现次数,最后与总次数相除算出概率 15 | func PrintProbability_Solution1(_ num: Int) -> [Int: Double]{ 16 | var result = [Int: Double]() 17 | guard num > 0 else { 18 | return result 19 | } 20 | let maxSum = num * DiceMaxValue 21 | //num个骰子的和是不会出现 (1到[num-1]) 这几个数字的,所以可能出现的和总数是 maxSum - num + 1 22 | var probabilities = Array.init(repeating: 0, count: maxSum - num + 1) 23 | probabilities = Probability(num, probabilities) 24 | let total = (pow(Decimal(DiceMaxValue), num) as NSDecimalNumber).doubleValue 25 | for (index, probability) in probabilities.enumerated() { 26 | result[index + num] = Double(probability) / total 27 | } 28 | return result 29 | } 30 | private func Probability(_ num: Int, _ probabilities: [Int]) -> [Int] { 31 | var probabilities = probabilities 32 | for index in 1...DiceMaxValue { 33 | probabilities = Probability(num, num, index, probabilities) 34 | } 35 | return probabilities; 36 | } 37 | private func Probability(_ original: Int, _ current: Int, _ sum: Int, _ probabilities: [Int] ) -> [Int] { 38 | var probabilities = probabilities 39 | if current == 1 { 40 | probabilities[sum - original] += 1 41 | } else { 42 | for index in 1...DiceMaxValue { 43 | probabilities = Probability(original, current - 1, sum + index, probabilities) 44 | } 45 | } 46 | return probabilities 47 | } 48 | 49 | // 方法二 利用两个数组 50 | func PrintProbability_Solution2(_ num: Int) -> [Int: Double] { 51 | var result = [Int: Double]() 52 | guard num > 0 else { 53 | return result 54 | } 55 | var probabilities = [[Int]]() 56 | probabilities.append(Array.init(repeating: 0, count: DiceMaxValue * num + 1 )) 57 | probabilities.append(Array.init(repeating: 0, count: DiceMaxValue * num + 1 )) 58 | var flag = 0 59 | for index in 1...DiceMaxValue { 60 | probabilities[flag][index] = 1 61 | } 62 | for r in 2...num { 63 | //将另一个数组的小于r的元素都设置为 0 (因为r个骰子的和不会比r小) 64 | for index in 0..= num { 79 | result[index] = Double(probability) / total 80 | } 81 | } 82 | return result 83 | } 84 | } 85 | 86 | class UnitTests: XCTestCase { 87 | var solution: Solution! 88 | 89 | override func setUp() { 90 | super.setUp() 91 | solution = Solution() 92 | } 93 | //本题目不太好测试 😓 94 | func testCase1() { 95 | let result1 = solution.PrintProbability_Solution1(2) 96 | let result2 = solution.PrintProbability_Solution2(2) 97 | } 98 | } 99 | 100 | UnitTests.defaultTestSuite.run() 101 | -------------------------------------------------------------------------------- /60_DicesProbability.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /61_ContinousCards.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | //================================================================== 2 | // 《剑指Offer——名企面试官精讲典型编程题》代码 3 | //================================================================== 4 | // 面试题61:扑克牌的顺子 5 | // 题目:从扑克牌中随机抽5张牌,判断是不是一个顺子,即这5张牌是不是连续的。 6 | // 2~10为数字本身,A为1,J为11,Q为12,K为13,而大、小王可以看成任意数字。 7 | 8 | import Foundation 9 | import XCTest 10 | 11 | class Solution { 12 | /** 13 | 判断5张扑克牌是不是顺子 14 | - Parameters: 15 | - nums:数组 16 | - Returns: 是否顺子 17 | 解法:将输入的数字排序,统计出0的个数,在从非0数字开始计算当前数字与下一个数字之间的间隙(gap) 18 | 如果间隙大于0的个数则非顺子,否则为顺子 19 | */ 20 | 21 | func IsContinuous(_ nums: [Int]) -> Bool { 22 | guard nums.count > 0 else { 23 | return false 24 | } 25 | var nums = nums.sorted() 26 | let numberOfZero = nums.filter{$0 == 0}.count 27 | var numberOfGap = 0 28 | for index in numberOfZero.. numberOfZero ? false : true 35 | } 36 | } 37 | 38 | class UnitTests: XCTestCase { 39 | var solution: Solution! 40 | 41 | override func setUp() { 42 | super.setUp() 43 | solution = Solution() 44 | } 45 | 46 | func testCase1() { 47 | let nums = [1,3,2,5,4] 48 | XCTAssertEqual(true, solution.IsContinuous(nums)) 49 | } 50 | func testCase2() { 51 | let nums = [1,3,2,6,4] 52 | XCTAssertEqual(false, solution.IsContinuous(nums)) 53 | } 54 | func testCase3() { 55 | let nums = [0,3,2,6,4] 56 | XCTAssertEqual(true, solution.IsContinuous(nums)) 57 | } 58 | func testCase4() { 59 | let nums = [0,3,1,6,4] 60 | XCTAssertEqual(true, solution.IsContinuous(nums)) 61 | } 62 | func testCase5() { 63 | let nums = [1,3,0,5,0] 64 | XCTAssertEqual(true, solution.IsContinuous(nums)) 65 | } 66 | func testCase6() { 67 | let nums = [1,3,0,7,0] 68 | XCTAssertEqual(false, solution.IsContinuous(nums)) 69 | } 70 | func testCase7() { 71 | let nums = [1,0,0,5,0] 72 | XCTAssertEqual(true, solution.IsContinuous(nums)) 73 | } 74 | func testCase8() { 75 | let nums = [1,0,0,7,0] 76 | XCTAssertEqual(false, solution.IsContinuous(nums)) 77 | } 78 | func testCase9() { 79 | let nums = [3,0,0,0,0] 80 | XCTAssertEqual(true, solution.IsContinuous(nums)) 81 | } 82 | func testCase10() { 83 | let nums = [0,3,2,6,4] 84 | XCTAssertEqual(true, solution.IsContinuous(nums)) 85 | } 86 | func testCase11() { 87 | let nums = [1,0,0,1,0] 88 | XCTAssertEqual(false, solution.IsContinuous(nums)) 89 | } 90 | func testCase12() { 91 | let nums:[Int] = [] 92 | XCTAssertEqual(false, solution.IsContinuous(nums)) 93 | } 94 | } 95 | 96 | UnitTests.defaultTestSuite.run() 97 | -------------------------------------------------------------------------------- /61_ContinousCards.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /62_LastNumberInCircle.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | //================================================================== 2 | // 《剑指Offer——名企面试官精讲典型编程题》代码 3 | //================================================================== 4 | // 面试题62:圆圈中最后剩下的数字 5 | // 题目:0, 1, …, n-1这n个数字排成一个圆圈,从数字0开始每次从这个圆圈里 6 | // 删除第m个数字。求出这个圆圈里剩下的最后一个数字。 7 | 8 | import Foundation 9 | import XCTest 10 | 11 | class Solution { 12 | /** 13 | 获取圆圈中最后剩下的数字 14 | - Parameters: 15 | - n:表示圆圈中的数字为 1...n-1 16 | - m:表示每次删除第m个数字 17 | - Returns: 最后一个数字 18 | */ 19 | func LastRemaining_Solution1(n: Int, m: Int) -> Int? { 20 | guard n > 0 && m > 0 else { 21 | return nil 22 | } 23 | var nums = [Int]() //用数组来模拟圆圈中的数字 24 | for i in 0.. 1 { 29 | for _ in 1.. Int? { 51 | guard n > 0 && m > 0 else { 52 | return nil 53 | } 54 | var last = 0 55 | for i in 2...n { 56 | last = (last + m) % i 57 | } 58 | return last 59 | } 60 | } 61 | 62 | class UnitTests: XCTestCase { 63 | var solution: Solution! 64 | 65 | override func setUp() { 66 | super.setUp() 67 | solution = Solution() 68 | } 69 | 70 | func testCase1() { 71 | XCTAssertEqual(3, solution.LastRemaining_Solution1(n: 5, m: 3)) 72 | XCTAssertEqual(3, solution.LastRemaining_Solution2(n: 5, m: 3)) 73 | } 74 | func testCase2() { 75 | XCTAssertEqual(2, solution.LastRemaining_Solution1(n: 5, m: 2)) 76 | XCTAssertEqual(2, solution.LastRemaining_Solution2(n: 5, m: 2)) 77 | } 78 | func testCase3() { 79 | XCTAssertEqual(4, solution.LastRemaining_Solution1(n: 6, m: 7)) 80 | XCTAssertEqual(4, solution.LastRemaining_Solution2(n: 6, m: 7)) 81 | } 82 | func testCase4() { 83 | XCTAssertEqual(3, solution.LastRemaining_Solution1(n: 6, m: 6)) 84 | XCTAssertEqual(3, solution.LastRemaining_Solution2(n: 6, m: 6)) 85 | } 86 | func testCase5() { 87 | XCTAssertEqual(nil, solution.LastRemaining_Solution1(n: 0, m: 0)) 88 | XCTAssertEqual(nil, solution.LastRemaining_Solution2(n: 0, m: 0)) 89 | } 90 | func testCase6() { 91 | //XCTAssertEqual(1027, solution.LastRemaining_Solution1(n: 4000, m: 997)) 92 | XCTAssertEqual(1027, solution.LastRemaining_Solution2(n: 4000, m: 997)) 93 | } 94 | } 95 | 96 | UnitTests.defaultTestSuite.run() 97 | -------------------------------------------------------------------------------- /62_LastNumberInCircle.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /63_MaximalProfit.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | //================================================================== 2 | // 《剑指Offer——名企面试官精讲典型编程题》代码 3 | //================================================================== 4 | // 面试题63:股票的最大利润 5 | // 题目:假设把某股票的价格按照时间先后顺序存储在数组中,请问买卖交易该股 6 | // 票可能获得的利润是多少?例如一只股票在某些时间节点的价格为{9, 11, 8, 5, 7 | // 7, 12, 16, 14}。如果我们能在价格为5的时候买入并在价格为16时卖出,则能 8 | // 收获最大的利润11。 9 | 10 | import Foundation 11 | import XCTest 12 | 13 | class Solution { 14 | /** 15 | 获取股票的最大利润 16 | - Parameters: 17 | - nums:股票价格数组 18 | - Returns: 最大利益 19 | */ 20 | func MaxDiff(_ nums:[Int]) -> Int? { 21 | guard nums.count > 1 else { 22 | //必须有2个或以上价格 23 | return nil 24 | } 25 | var min = nums[0] 26 | var maxDiff = nums[1] - min 27 | for i in 2.. maxDiff { 33 | maxDiff = currentDiff 34 | } 35 | } 36 | return maxDiff 37 | } 38 | } 39 | 40 | class UnitTests: XCTestCase { 41 | var solution: Solution! 42 | 43 | override func setUp() { 44 | super.setUp() 45 | solution = Solution() 46 | } 47 | //价格随机 48 | func testCase1() { 49 | let nums = [4,1,3,2,5] 50 | XCTAssertEqual(4, solution.MaxDiff(nums)) 51 | } 52 | //价格递增 53 | func testCase2() { 54 | let nums = [1,2,4,7,11,16] 55 | XCTAssertEqual(15, solution.MaxDiff(nums)) 56 | } 57 | //价格递减 58 | func testCase3() { 59 | let nums = [16,11,7,4,2,1] 60 | XCTAssertEqual(-1, solution.MaxDiff(nums)) 61 | } 62 | //价格不变 63 | func testCase4() { 64 | let nums = [16,16,16,16,16] 65 | XCTAssertEqual(0, solution.MaxDiff(nums)) 66 | } 67 | func testCase5() { 68 | let nums = [9,11,5,7,16,1,4,2] 69 | XCTAssertEqual(11, solution.MaxDiff(nums)) 70 | } 71 | func testCase6() { 72 | let nums = [2,4] 73 | XCTAssertEqual(2, solution.MaxDiff(nums)) 74 | } 75 | func testCase7() { 76 | let nums = [4,2] 77 | XCTAssertEqual(-2, solution.MaxDiff(nums)) 78 | } 79 | func testCase8() { 80 | let nums = [Int]() 81 | XCTAssertEqual(nil, solution.MaxDiff(nums)) 82 | } 83 | } 84 | 85 | UnitTests.defaultTestSuite.run() 86 | -------------------------------------------------------------------------------- /63_MaximalProfit.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /64_Accumulate.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | //================================================================== 2 | // 《剑指Offer——名企面试官精讲典型编程题》代码 3 | //================================================================== 4 | // 面试题64:求1+2+…+n 5 | // 题目:求1+2+…+n,要求不能使用乘除法、for、while、if、else、switch、case 6 | // 等关键字及条件判断语句(A?B:C)。 7 | 8 | import Foundation 9 | import XCTest 10 | 11 | /* 12 | * 方法一 13 | * 通过 DispatchQueue.concurrentPerform 重复实例化Solution1对象 14 | * 然后利用 static 变量存储中间值 15 | */ 16 | class Solution1 { 17 | private static var N:Int = 0 18 | private static var Sum:Int = 0 19 | init() { 20 | Solution1.N = Solution1.N + 1 21 | Solution1.Sum = Solution1.Sum + Solution1.N 22 | } 23 | static func Reset(){ 24 | N = 0 25 | Sum = 0 26 | } 27 | static func GetSum(_ n: Int) -> Int { 28 | let queue = DispatchQueue(label: "64_Accumulate"); 29 | DispatchQueue.concurrentPerform(iterations: n) { i in 30 | queue.sync { 31 | _ = Solution1() 32 | } 33 | } 34 | let result = Sum 35 | Reset() 36 | return result 37 | } 38 | } 39 | 40 | /* 41 | * 方法二 42 | * 利用数字转成bool,再转成0和1,执行相应的函数(clourse),0的时候递归终止并返回最终的和 43 | */ 44 | class Solution2 { 45 | typealias sumFunc = (Int) -> Int 46 | var funs = Array() 47 | init() { 48 | funs.append({(i) in 49 | return 0 50 | }) 51 | funs.append({ [unowned self](i) in 52 | let index = Int(truncating: Bool(truncating: i as NSNumber) as NSNumber) 53 | return self.funs[index](i - 1) + i 54 | }) 55 | } 56 | func GetSum(_ n:Int) -> Int { 57 | return funs[1](n) 58 | } 59 | } 60 | 61 | class UnitTests: XCTestCase { 62 | 63 | override func setUp() { 64 | super.setUp() 65 | } 66 | 67 | func testCase1() { 68 | XCTAssertEqual(1, Solution1.GetSum(1)) 69 | XCTAssertEqual(15, Solution1.GetSum(5)) 70 | XCTAssertEqual(55, Solution1.GetSum(10)) 71 | XCTAssertEqual(0, Solution1.GetSum(0)) 72 | } 73 | func testCase2() { 74 | let solution2 = Solution2() 75 | XCTAssertEqual(1, solution2.GetSum(1)) 76 | XCTAssertEqual(15, solution2.GetSum(5)) 77 | XCTAssertEqual(55, solution2.GetSum(10)) 78 | XCTAssertEqual(0, solution2.GetSum(0)) 79 | } 80 | } 81 | 82 | UnitTests.defaultTestSuite.run() 83 | -------------------------------------------------------------------------------- /64_Accumulate.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /65_AddTwoNumbers.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | //================================================================== 2 | // 《剑指Offer——名企面试官精讲典型编程题》代码 3 | //================================================================== 4 | // 面试题65:不用加减乘除做加法 5 | // 题目:写一个函数,求两个整数之和,要求在函数体内不得使用+、-、×、÷ 6 | // 四则运算符号。 7 | import Foundation 8 | import XCTest 9 | 10 | class Solution1 { 11 | /* 12 | 不使用加减乘除做加法 13 | - Parameters: 14 | - num1: 数字1 15 | - num2: 数字2 16 | - Returns: 两数之和 17 | 解法:num1^num2 = num1+num2(不考虑进位),进位计算: (num1 & num2) << 1 18 | */ 19 | func sum(num1:Int, with num2:Int) -> Int { 20 | var num1 = num1 21 | var num2 = num2 22 | repeat { 23 | let sum = num1 ^ num2 24 | let carry = (num1 & num2) << 1 25 | num1 = sum 26 | num2 = carry 27 | } while (num2 != 0); 28 | return num1 29 | } 30 | } 31 | 32 | class UnitTests: XCTestCase { 33 | let solution1 = Solution1() 34 | override func setUp() { 35 | super.setUp() 36 | } 37 | func testCase1() { 38 | XCTAssertEqual(3, solution1.sum(num1: 1, with: 2)) 39 | XCTAssertEqual(1010, solution1.sum(num1: 111, with: 899)) 40 | XCTAssertEqual(-1, solution1.sum(num1: 1, with: -2)) 41 | XCTAssertEqual(3, solution1.sum(num1: 3, with: 0)) 42 | XCTAssertEqual(-4, solution1.sum(num1: -4, with: 0)) 43 | XCTAssertEqual(-10, solution1.sum(num1: -2, with: -8)) 44 | } 45 | } 46 | 47 | UnitTests.defaultTestSuite.run() 48 | -------------------------------------------------------------------------------- /65_AddTwoNumbers.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /66_ConstuctArray.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | //================================================================== 2 | // 《剑指Offer——名企面试官精讲典型编程题》代码 3 | //================================================================== 4 | // 面试题66:构建乘积数组 5 | // 题目:给定一个数组A[0, 1, …, n-1],请构建一个数组B[0, 1, …, n-1],其 6 | // 中B中的元素B[i] =A[0]×A[1]×… ×A[i-1]×A[i+1]×…×A[n-1]。不能使用除法。 7 | import Foundation 8 | import XCTest 9 | 10 | class Solution1 { 11 | 12 | /* 13 | 构建乘积数组 14 | - Parameters: 15 | - nums: 数组A 16 | - Returns: 乘积结果 数组B 17 | */ 18 | func BuildProductionArray(nums:[Int]) -> [Int] { 19 | guard nums.count > 0 else { 20 | return [Int]() 21 | } 22 | var output = Array(repeating: 0, count: nums.count) 23 | output[0] = 1 24 | for index in 1.. 2 | 3 | 4 | -------------------------------------------------------------------------------- /67_StringToInt.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | //================================================================== 2 | // 《剑指Offer——名企面试官精讲典型编程题》代码 3 | //================================================================== 4 | // 面试题67:把字符串转换成整数 5 | // 题目:请你写一个函数StrToInt,实现把字符串转换成整数这个功能。当然,不 6 | // 能使用atoi或者其他类似的库函数。 7 | 8 | import Foundation 9 | import XCTest 10 | 11 | class Solution1 { 12 | /* 13 | 将字符串转换为整形 14 | - Parameters: 15 | - str: 需要转换成数字的字符串 16 | - Returns: 转换之后的整数 17 | */ 18 | func StrToInt(str: String) -> Int? { 19 | var strArray = Array(str) 20 | guard strArray.count > 0 else { 21 | return nil 22 | } 23 | var minus = false 24 | if strArray.first == "-" { 25 | minus = true 26 | strArray.removeFirst() 27 | } 28 | else if strArray.first == "+" { 29 | strArray.removeFirst() 30 | } 31 | var num: UInt = 0 32 | for item in strArray { 33 | if let digit = Int(String(item)) { 34 | num = num * 10 + UInt(digit) 35 | if num > UInt(Int64.max) && !minus { 36 | return nil 37 | } 38 | if num > UInt(Int64.max) + 1 && minus { 39 | return nil 40 | } 41 | } 42 | else { 43 | return nil 44 | } 45 | } 46 | if num > Int.max && minus { 47 | return Int.min 48 | } else { 49 | return Int(num) * (minus ? -1 : 1) 50 | } 51 | } 52 | } 53 | 54 | class UnitTests: XCTestCase { 55 | let solution1 = Solution1() 56 | override func setUp() { 57 | super.setUp() 58 | } 59 | func testCase1() { 60 | XCTAssertEqual(nil, solution1.StrToInt(str: "")) 61 | XCTAssertEqual(123, solution1.StrToInt(str: "123")) 62 | XCTAssertEqual(123, solution1.StrToInt(str: "+123")) 63 | XCTAssertEqual(-123, solution1.StrToInt(str: "-123")) 64 | XCTAssertEqual(nil, solution1.StrToInt(str: "1a23")) 65 | XCTAssertEqual(0, solution1.StrToInt(str: "+0")) 66 | XCTAssertEqual(0, solution1.StrToInt(str: "-0")) 67 | XCTAssertEqual(0, solution1.StrToInt(str: "+")) 68 | XCTAssertEqual(0, solution1.StrToInt(str: "-")) 69 | } 70 | 71 | func testCase2() { 72 | //Int.max = 9223372036854775807 73 | //Int.min = -9223372036854775808 74 | XCTAssertEqual(9223372036854775807, solution1.StrToInt(str: "+9223372036854775807")) 75 | XCTAssertEqual(nil, solution1.StrToInt(str: "+9223372036854775808")) 76 | XCTAssertEqual(-9223372036854775808, solution1.StrToInt(str: "-9223372036854775808")) 77 | XCTAssertEqual(nil, solution1.StrToInt(str: "-9223372036854775809")) 78 | } 79 | } 80 | 81 | UnitTests.defaultTestSuite.run() 82 | -------------------------------------------------------------------------------- /67_StringToInt.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /68_CommonParentInTree.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | //================================================================== 2 | // 《剑指Offer——名企面试官精讲典型编程题》代码 3 | //================================================================== 4 | // 面试题68:树中两个结点的最低公共祖先 5 | // 题目:输入两个树结点,求它们的最低公共祖先。 6 | 7 | import Foundation 8 | import XCTest 9 | 10 | //树结构 11 | class TreeNode: Equatable { 12 | var children: [TreeNode] 13 | var value: Int 14 | 15 | init(value: Int, children: [TreeNode]) { 16 | self.value = value 17 | self.children = children 18 | } 19 | static func ==(left: TreeNode, right: TreeNode) -> Bool { 20 | return left.value == right.value 21 | } 22 | } 23 | 24 | class Solution1 { 25 | /* 26 | 查找树中两个结点的最低公共祖先 27 | - Parameters: 28 | - root: 树的根节点 29 | - node1: 节点1 30 | - node2: 节点2 31 | - Returns: 查找到的公共祖先 32 | */ 33 | func GetLastCommonParent(root: TreeNode, node1: TreeNode, node2: TreeNode) -> TreeNode? { 34 | var path1 = [TreeNode](), path2 = [TreeNode]() 35 | GetNodePath(root: root, node: node1, path: &path1) 36 | GetNodePath(root: root, node: node2, path: &path2) 37 | return GetLastCommonNode(path1: path1, path2: path2) 38 | } 39 | /* 40 | 返回从node到root所有节点 41 | - Parameters: 42 | - root: 树的根节点 43 | - node: 节点 44 | - Returns: 是否找到 45 | */ 46 | func GetNodePath(root: TreeNode, node: TreeNode, path: inout [TreeNode]) -> Bool { 47 | if root == node { 48 | return true 49 | } 50 | path.append(root) 51 | var found = false 52 | for child in root.children { 53 | found = GetNodePath(root: child, node: node, path: &path) 54 | if found { 55 | break 56 | } 57 | } 58 | if !found { 59 | path.removeLast() 60 | } 61 | return found 62 | } 63 | /* 64 | 根据两条路径查找最后公共祖先,两条路径都是从根节点在前 65 | - Parameters: 66 | - path1: 路径1 67 | - path2: 路径2 68 | - Returns: 查找最后公共祖先 69 | */ 70 | func GetLastCommonNode(path1: [TreeNode], path2: [TreeNode]) -> TreeNode? { 71 | var commonNode: TreeNode? = nil 72 | for i in stride(from: 0, to: path1.count, by: 1) { 73 | if i < path2.count && path1[i] == path2[i] { 74 | commonNode = path1[i] 75 | } else { 76 | return commonNode 77 | } 78 | } 79 | return commonNode 80 | } 81 | } 82 | 83 | class UnitTests: XCTestCase { 84 | let solution1 = Solution1() 85 | override func setUp() { 86 | super.setUp() 87 | } 88 | 89 | // 形状普通的树 90 | // 1 91 | // / \ 92 | // 2 3 93 | // / \ 94 | // 4 5 95 | // / \ / | \ 96 | // 6 7 8 9 10 97 | func testCase1() { 98 | let node10 = TreeNode(value: 10, children: []) 99 | let node9 = TreeNode(value: 9, children: []) 100 | let node8 = TreeNode(value: 8, children: []) 101 | let node7 = TreeNode(value: 7, children: []) 102 | let node6 = TreeNode(value: 6, children: []) 103 | let node5 = TreeNode(value: 5, children: [node8,node9,node10]) 104 | let node4 = TreeNode(value: 4, children: [node6,node7]) 105 | let node3 = TreeNode(value: 3, children: []) 106 | let node2 = TreeNode(value: 2, children: [node4,node5]) 107 | let node1 = TreeNode(value: 1, children: [node2,node3]) 108 | XCTAssertEqual(node2, solution1.GetLastCommonParent(root: node1, node1: node6, node2: node8)) 109 | } 110 | // 树退化成一个链表 111 | // 1 112 | // / 113 | // 2 114 | // / 115 | // 3 116 | // / 117 | // 4 118 | // / 119 | // 5 120 | func testCase2() { 121 | let node5 = TreeNode(value: 5, children: []) 122 | let node4 = TreeNode(value: 4, children: [node5]) 123 | let node3 = TreeNode(value: 3, children: [node4]) 124 | let node2 = TreeNode(value: 2, children: [node3]) 125 | let node1 = TreeNode(value: 1, children: [node2]) 126 | XCTAssertEqual(node3, solution1.GetLastCommonParent(root: node1, node1: node4, node2: node5)) 127 | } 128 | // 树退化成一个链表,一个结点不在树中 129 | // 1 130 | // / 131 | // 2 132 | // / 133 | // 3 134 | // / 135 | // 4 136 | // / 137 | // 5 138 | func testCase3() { 139 | let node5 = TreeNode(value: 5, children: []) 140 | let node4 = TreeNode(value: 4, children: [node5]) 141 | let node3 = TreeNode(value: 3, children: [node4]) 142 | let node2 = TreeNode(value: 2, children: [node3]) 143 | let node1 = TreeNode(value: 1, children: [node2]) 144 | let node6 = TreeNode(value: 6, children: []) 145 | XCTAssertEqual(nil, solution1.GetLastCommonParent(root: node1, node1: node4, node2: node6)) 146 | } 147 | } 148 | 149 | UnitTests.defaultTestSuite.run() 150 | -------------------------------------------------------------------------------- /68_CommonParentInTree.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## 《剑指Offer》第二版源代码 Swift 版本 2 | 作者原版:[Github](https://github.com/zhedahht/CodingInterviewChinese2) 3 | 购买书籍:[亚马逊](https://www.amazon.cn/dp/B00FF1Y0FU/ref=sr_1_2?ie=UTF8&qid=1544017744&sr=8-2&keywords=%E5%89%91%E6%8C%87offer)/[京东](https://item.jd.com/12163054.html) 4 | 5 | --------------------------------------------------------------------------------