From c14c2297f1fa2db45fe5eda6e0661a669944c716 Mon Sep 17 00:00:00 2001 From: zhenzi Date: Sat, 17 Jul 2021 12:13:15 +0800 Subject: [PATCH 01/10] =?UTF-8?q?=E4=B8=BA=E6=95=B0=E7=BB=84=E7=AF=87=20?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=20Swift=20=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../数组篇/leetcode1052爱生气的书店老板.md | 42 ++++- .../leetcode1438绝对值不超过限制的最长子数组.md | 149 ++++++++++++++++++ .../数组篇/leetcode1两数之和.md | 43 +++++ .../数组篇/leetcode219数组中重复元素2.md | 51 ++++++ .../数组篇/leetcode27移除元素.md | 20 +++ .../数组篇/leetcode41缺失的第一个正数.md | 66 ++++++++ .../数组篇/leetcode485最大连续1的个数.md | 45 ++++++ .../数组篇/leetcode54螺旋矩阵.md | 35 ++++ .../数组篇/leetcode560和为K的子数组.md | 26 +++ .../数组篇/leetcode59螺旋矩阵2.md | 79 ++++++++++ animation-simulation/数组篇/leetcode66加一.md | 20 +++ .../数组篇/leetcode75颜色分类.md | 67 ++++++++ .../数组篇/剑指offer3数组中重复的数.md | 41 +++++ .../数组篇/长度最小的子数组.md | 19 +++ 14 files changed, 702 insertions(+), 1 deletion(-) diff --git a/animation-simulation/数组篇/leetcode1052爱生气的书店老板.md b/animation-simulation/数组篇/leetcode1052爱生气的书店老板.md index b9a94ad..79bef86 100644 --- a/animation-simulation/数组篇/leetcode1052爱生气的书店老板.md +++ b/animation-simulation/数组篇/leetcode1052爱生气的书店老板.md @@ -114,5 +114,45 @@ class Solution: ans = max(ans, t) return ans ``` - +Swift Code + +```swift +class Solution { + func maxSatisfied(_ customers: [Int], _ grumpy: [Int], _ minutes: Int) -> Int { + let len = customers.count + var winSum = 0, rightSum = 0, leftSum = 0 + // 右区间的值 + for i in minutes.. Int { + var maxQueue:[Int] = [] + var minQueue:[Int] = [] + let len = nums.count + var right = 0, left = 0, maxWin = 0 + while right < len { + while !maxQueue.isEmpty && (maxQueue.last! < nums[right]) { + maxQueue.removeLast() + } + while !minQueue.isEmpty && (minQueue.last! > nums[right]) { + minQueue.removeLast() + } + maxQueue.append(nums[right]) + minQueue.append(nums[right]) + while (maxQueue.first! - minQueue.first!) > limit { + if maxQueue.first! == nums[left] { + maxQueue.removeFirst() + } + if minQueue.first! == nums[left] { + minQueue.removeFirst() + } + left += 1 + } + maxWin = max(maxWin, right - left + 1) + right += 1 + } + return maxWin + } +} +``` + +Swift:使用双端队列(击败了100.00%) + +```swift +class Solution { + func longestSubarray(_ nums: [Int], _ limit: Int) -> Int { + var maxQueue = Deque.init() + var minQueue = Deque.init() + let len = nums.count + var right = 0, left = 0, maxWin = 0 + while right < len { + while !maxQueue.isEmpty && (maxQueue.peekBack()! < nums[right]) { + maxQueue.dequeueBack() + } + while !minQueue.isEmpty && (minQueue.peekBack()! > nums[right]) { + minQueue.dequeueBack() + } + maxQueue.enqueue(nums[right]) + minQueue.enqueue(nums[right]) + while (maxQueue.peekFront()! - minQueue.peekFront()!) > limit { + if maxQueue.peekFront()! == nums[left] { + maxQueue.dequeue() + } + if minQueue.peekFront()! == nums[left] { + minQueue.dequeue() + } + left += 1 + } + maxWin = max(maxWin, right - left + 1) + right += 1 + } + return maxWin + } + + // 双端队列数据结构 + public struct Deque { + private var array: [T?] + private var head: Int + private var capacity: Int + private let originalCapacity: Int + + public init(_ capacity: Int = 10) { + self.capacity = max(capacity, 1) + originalCapacity = self.capacity + array = [T?](repeating: nil, count: capacity) + head = capacity + } + + public var isEmpty: Bool { + return count == 0 + } + + public var count: Int { + return array.count - head + } + + public mutating func enqueue(_ element: T) { + array.append(element) + } + + public mutating func enqueueFront(_ element: T) { + if head == 0 { + capacity *= 2 + let emptySpace = [T?](repeating: nil, count: capacity) + array.insert(contentsOf: emptySpace, at: 0) + head = capacity + } + + head -= 1 + array[head] = element + } + + public mutating func dequeue() -> T? { + guard head < array.count, let element = array[head] else { return nil } + + array[head] = nil + head += 1 + + if capacity >= originalCapacity && head >= capacity*2 { + let amountToRemove = capacity + capacity/2 + array.removeFirst(amountToRemove) + head -= amountToRemove + capacity /= 2 + } + return element + } + + public mutating func dequeueBack() -> T? { + if isEmpty { + return nil + } else { + return array.removeLast() + } + } + + public func peekFront() -> T? { + if isEmpty { + return nil + } else { + return array[head] + } + } + + public func peekBack() -> T? { + if isEmpty { + return nil + } else { + return array.last! + } + } + } +} +``` + diff --git a/animation-simulation/数组篇/leetcode1两数之和.md b/animation-simulation/数组篇/leetcode1两数之和.md index 89db733..b226bc1 100644 --- a/animation-simulation/数组篇/leetcode1两数之和.md +++ b/animation-simulation/数组篇/leetcode1两数之和.md @@ -76,6 +76,32 @@ class Solution: return rearr ``` +Swift Code: + +```swift +class Solution { + func twoSum(_ nums: [Int], _ target: Int) -> [Int] { + let count = nums.count + if count < 2 { + return [0] + } + + var rearr: [Int] = [] + // 查询元素 + for i in 0.. [Int] { + var m:[Int:Int] = [:] + for i in 0.. Bool { + if nums.count == 0 { + return false + } + var dict:[Int:Int] = [:] + for i in 0.. Bool { + if nums.count == 0 { + return false + } + var set:Set = [] + for i in 0.. k { + set.remove(nums[i - k]) + } + } + return false + } +} +``` diff --git a/animation-simulation/数组篇/leetcode27移除元素.md b/animation-simulation/数组篇/leetcode27移除元素.md index db107bc..75a5f61 100644 --- a/animation-simulation/数组篇/leetcode27移除元素.md +++ b/animation-simulation/数组篇/leetcode27移除元素.md @@ -164,3 +164,23 @@ public: }; ``` +Swift Code + +```swift +class Solution { + func removeElement(_ nums: inout [Int], _ val: Int) -> Int { + if nums.count == 0 { + return 0 + } + var i = 0 + for j in 0.. Int { + if nums.count == 0 { + return 1 + } + // 因为是返回第一个正整数,不包括 0,所以需要长度加1,细节1 + var res:[Int] = Array.init(repeating: 0, count: nums.count + 1) + // 将数组元素添加到辅助数组中 + for x in nums { + if x > 0 && x < res.count { + res[x] = x + } + } + // 遍历查找,发现不一样时直接返回 + for i in 1.. Int { + var nums = nums + let len = nums.count + if len == 0 { + return 1 + } + // 遍历数组 + for i in 0.. 0 + && nums[i] < len + 1 + && nums[i] != i + 1 + && nums[i] != nums[nums[i] - 1] + { + //nums.swapAt(i, (nums[i] - 1)) // 系统方法 + self.swap(&nums, i, (nums[i] - 1)) // 自定义方法 + } + } + // 遍历寻找缺失的正整数 + for i in 0.. Int { + + var left = 0, right = 0, res = 0 + let len = nums.count + while right < len { + if nums[right] == 1 { + right += 1 + continue + } + // 保存最大值 + res = max(res, right - left) + // 跳过 0 的情况 + while right < len && nums[right] == 0 { + right += 1 + } + // 同一起点继续遍历 + left = right + } + return max(res, right - left) + } +} +``` 刚才的效率虽然相对高一些,但是代码不够优美,欢迎各位改进,下面我们说一下另外一种情况,一个特别容易理解的方法。 @@ -132,3 +158,22 @@ class Solution: return ans ``` +Swift Code + +```swift +class Solution { + func findMaxConsecutiveOnes(_ nums: [Int]) -> Int { + let len = nums.count + var maxCount = 0, count = 0 + for i in 0.. [Int] { + var arr:[Int] = [] + var left = 0, right = matrix[0].count - 1 + var top = 0, down = matrix.count - 1 + + while (true) { + for i in left...right { + arr.append(matrix[top][i]) + } + top += 1 + if top > down { break } + for i in top...down { + arr.append(matrix[i][right]) + } + right -= 1 + if left > right { break} + for i in stride(from: right, through: left, by: -1) { + arr.append(matrix[down][i]) + } + down -= 1 + if top > down { break} + for i in stride(from: down, through: top, by: -1) { + arr.append(matrix[i][left]) + } + left += 1 + if left > right { break} + } + + return arr + } +} +``` diff --git a/animation-simulation/数组篇/leetcode560和为K的子数组.md b/animation-simulation/数组篇/leetcode560和为K的子数组.md index 8e81e3e..6c4f372 100644 --- a/animation-simulation/数组篇/leetcode560和为K的子数组.md +++ b/animation-simulation/数组篇/leetcode560和为K的子数组.md @@ -45,6 +45,8 @@ class Solution { Python3版本的代码会超时 +Swift版本的代码会超时 + 下面我们我们使用前缀和的方法来解决这个题目,那么我们先来了解一下前缀和是什么东西。其实这个思想我们很早就接触过了。见下图 ![](https://cdn.jsdelivr.net/gh/tan45du/github.io.phonto2@master/myphoto/微信截图_20210113193831.4wk2b9zc8vm0.png) @@ -160,3 +162,27 @@ class Solution { } ``` +Swift Code + +```swift +class Solution { + func subarraySum(_ nums: [Int], _ k: Int) -> Int { + if nums.count == 0 { + return 0 + } + var map: [Int: Int] = [:] + map[0] = 1 // 需要添加入一个元素垫底,已支持前几位就满足的情况 + var presum = 0, count = 0 + + for x in nums { + presum += x + //当前前缀和已知,判断是否含有 presum - k的前缀和,那么我们就知道某一区间的和为 k 了。 + if let v = map[presum - k] { + count += v //获取presum-k前缀和出现次数 + } + map[presum] = (map[presum] ?? 0) + 1 + } + return count + } +} +``` diff --git a/animation-simulation/数组篇/leetcode59螺旋矩阵2.md b/animation-simulation/数组篇/leetcode59螺旋矩阵2.md index 50cf94c..42a1f0f 100644 --- a/animation-simulation/数组篇/leetcode59螺旋矩阵2.md +++ b/animation-simulation/数组篇/leetcode59螺旋矩阵2.md @@ -140,6 +140,43 @@ class Solution: return arr ``` +Swift Code: + +```swift +class Solution { + func spiralOrder(_ matrix: [[Int]]) -> [Int] { + var arr:[Int] = [] + var left = 0, right = matrix[0].count - 1 + var top = 0, down = matrix.count - 1 + + while (true) { + for i in left...right { + arr.append(matrix[top][i]) + } + top += 1 + if top > down { break } + for i in top...down { + arr.append(matrix[i][right]) + } + right -= 1 + if left > right { break} + for i in stride(from: right, through: left, by: -1) { + arr.append(matrix[down][i]) + } + down -= 1 + if top > down { break} + for i in stride(from: down, through: top, by: -1) { + arr.append(matrix[i][left]) + } + left += 1 + if left > right { break} + } + + return arr + } +} +``` + 我们仅仅是将 54 反过来了,往螺旋矩阵里面插值,下面我们直接看代码吧,大家可以也可以对其改进,大家可以思考一下,如果修改能够让代码更简洁! Java Code: @@ -226,3 +263,45 @@ class Solution: return arr.tolist() ``` +Swift Code: + +```swift +class Solution { + func generateMatrix(_ n: Int) -> [[Int]] { + var arr:[[Int]] = Array.init(repeating: Array.init(repeating: 0, count: n), count: n) + var left = 0, right = n - 1 + var top = 0, bottom = n - 1 + var num = 1, numSize = n * n + + while true { + for i in left...right { + arr[top][i] = num + num += 1 + } + top += 1 + if num > numSize { break} + for i in top...bottom { + arr[i][right] = num + num += 1 + } + right -= 1 + if num > numSize { break} + for i in stride(from: right, through: left, by: -1) { + arr[bottom][i] = num + num += 1 + } + bottom -= 1 + if num > numSize { break} + for i in stride(from: bottom, through: top, by: -1) { + arr[i][left] = num + num += 1 + } + left += 1 + if num > numSize { break} + } + + return arr + } +} +``` + diff --git a/animation-simulation/数组篇/leetcode66加一.md b/animation-simulation/数组篇/leetcode66加一.md index 3030fee..f3daa00 100644 --- a/animation-simulation/数组篇/leetcode66加一.md +++ b/animation-simulation/数组篇/leetcode66加一.md @@ -85,3 +85,23 @@ class Solution: arr[0] = 1 return arr ``` + +Swift Code: + +```swift +class Solution { + func plusOne(_ digits: [Int]) -> [Int] { + let count = digits.count + var digits = digits + for i in stride(from: count - 1, through: 0, by: -1) { + digits[i] = (digits[i] + 1) % 10 + if digits[i] != 0 { + return digits + } + } + var arr: [Int] = Array.init(repeating: 0, count: count + 1) + arr[0] = 1 + return arr + } +} +``` diff --git a/animation-simulation/数组篇/leetcode75颜色分类.md b/animation-simulation/数组篇/leetcode75颜色分类.md index 7f125f1..cc16ed0 100644 --- a/animation-simulation/数组篇/leetcode75颜色分类.md +++ b/animation-simulation/数组篇/leetcode75颜色分类.md @@ -96,6 +96,38 @@ class Solution: nums[j] = temp ``` +Swift Code: + +```swift +class Solution { + func sortColors(_ nums: inout [Int]) { + + let count = nums.count + var left = 0, i = left, right = count - 1 + while i <= right { + if nums[i] == 2 { + //nums.swapAt(i, right) 直接调用系统方法 + self.swap(&nums, i, right) // 保持风格统一走自定义交换 + right -= 1 + } else if nums[i] == 0 { + //nums.swapAt(i, left) 直接调用系统方法 + self.swap(&nums, i, left) // 保持风格统一走自定义交换 + i += 1 + left += 1 + } else { + i += 1 + } + } + } + + func swap(_ nums: inout [Int], _ i: Int, _ j: Int) { + let temp = nums[i] + nums[i] = nums[j] + nums[j] = temp + } +} +``` + 另外我们看这段代码,有什么问题呢?那就是我们即使完全符合时,仍会交换元素,这样会大大降低我们的效率。 例如:[0,0,0,1,1,1,2,2,2] @@ -174,4 +206,39 @@ class Solution: temp = nums[i] nums[i] = nums[j] nums[j] = temp +``` + +Swift Code: + +```swift +class Solution { + func sortColors(_ nums: inout [Int]) { + + let count = nums.count + var left = 0, i = left, right = count - 1 + while i <= right { + if nums[i] == 0 { + //nums.swapAt(i, left) 直接调用系统方法 + self.swap(&nums, i, left) // 保持风格统一走自定义交换 + left += 1 + } + if nums[i] == 2 { + //nums.swapAt(i, right) 直接调用系统方法 + self.swap(&nums, i, right) // 保持风格统一走自定义交换 + right -= 1 + //如果不等于 1 则需要继续判断,所以不移动 i 指针,i-- + if nums[i] != 1 { + i -= 1 + } + } + i += 1 + } + } + + func swap(_ nums: inout [Int], _ i: Int, _ j: Int) { + let temp = nums[i] + nums[i] = nums[j] + nums[j] = temp + } +} ``` \ No newline at end of file diff --git a/animation-simulation/数组篇/剑指offer3数组中重复的数.md b/animation-simulation/数组篇/剑指offer3数组中重复的数.md index 9d09871..82c541f 100644 --- a/animation-simulation/数组篇/剑指offer3数组中重复的数.md +++ b/animation-simulation/数组篇/剑指offer3数组中重复的数.md @@ -61,6 +61,24 @@ class Solution: return -1 ``` +Swift Code: + +```swift +class Solution { + func findRepeatNumber(_ nums: [Int]) -> Int { + var set: Set = [] + for n in nums { + if set.contains(n) { // 如果发现某元素存在,则返回 + return n + } + set.insert(n) // 存入集合 + } + + return -1 + } +} +``` + #### **原地置换** **解析** @@ -136,3 +154,26 @@ class Solution: nums[temp] = temp return -1 ``` + +Swift Code: + +```swift +class Solution { + func findRepeatNumber(_ nums: [Int]) -> Int { + if nums.isEmpty { + return -1 + } + var nums = nums; + for i in 0.. Int { + + var sum = 0, windowlen = Int.max, i = 0 + for j in 0..= target { + windowlen = min(windowlen, j - i + 1) + sum -= nums[i] + i += 1 + } + } + return windowlen == Int.max ? 0 : windowlen + } +} +``` \ No newline at end of file From 7b55df11dcbe8cb38ccb44a51e3803da8317c297 Mon Sep 17 00:00:00 2001 From: frank-tian Date: Sat, 17 Jul 2021 22:28:06 +0800 Subject: [PATCH 02/10] =?UTF-8?q?=E4=B8=BA=E9=93=BE=E8=A1=A8=E7=AF=87=20?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=20Swift=20=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- animation-simulation/链表篇/234. 回文链表.md | 83 +++++++++++++++++++ .../链表篇/leetcode141环形链表.md | 17 ++++ .../链表篇/leetcode142环形链表2.md | 28 ++++++- .../链表篇/leetcode147对链表进行插入排序.md | 38 ++++++++- .../链表篇/leetcode206反转链表.md | 45 ++++++++++ .../链表篇/leetcode328奇偶链表.md | 24 ++++++ .../leetcode82删除排序链表中的重复元素II.md | 31 +++++++ .../链表篇/leetcode86分隔链表.md | 31 +++++++ .../链表篇/leetcode92反转链表2.md | 47 +++++++++++ .../链表篇/剑指Offer25合并两个排序的链表.md | 24 ++++++ .../剑指Offer52两个链表的第一个公共节点.md | 53 ++++++++++++ .../链表篇/剑指offer22倒数第k个节点.md | 25 ++++++ .../链表篇/面试题 02.03. 链表中间节点.md | 17 ++++ .../链表篇/面试题 02.05. 链表求和.md | 39 +++++++++ 14 files changed, 499 insertions(+), 3 deletions(-) diff --git a/animation-simulation/链表篇/234. 回文链表.md b/animation-simulation/链表篇/234. 回文链表.md index cee4772..8d77bc5 100644 --- a/animation-simulation/链表篇/234. 回文链表.md +++ b/animation-simulation/链表篇/234. 回文链表.md @@ -145,6 +145,35 @@ class Solution: return True ``` +Swift Code: + +```swift +class Solution { + func isPalindrome(_ head: ListNode?) -> Bool { + // 这里需要用动态数组,因为我们不知道链表的长度 + var arr:[Int?] = [] + var copynode = head + // 将链表的值复制到数组中 + while copynode != nil { + arr.append(copynode?.val) + copynode = copynode?.next + } + // 双指针遍历数组 + var back = 0, pro = arr.count - 1 + while back < pro { + // 判断两个指针的值是否相等 + if arr[pro] != arr[back] { + return false + } + // 移动指针 + back += 1 + pro -= 1 + } + return true + } +} +``` + 这个方法可以直接通过,但是这个方法需要辅助数组,那我们还有其他更好的方法吗? **双指针翻转链表法** @@ -375,3 +404,57 @@ class Solution: return low ``` +Swift Code: + +```swift +class Solution { + func isPalindrome(_ head: ListNode?) -> Bool { + if head == nil || head?.next == nil { + return true + } + //找到中间节点,也就是翻转的头节点,这个在昨天的题目中讲到 + //但是今天和昨天有一些不一样的地方就是,如果有两个中间节点返回第一个,昨天的题目是第二个 + var midnode = searchmidnode(head) + //原地翻转链表,需要两个辅助指针。这个也是面试题目,大家可以做一下 + //这里我们用的是midnode.next需要注意,因为我们找到的是中点,但是我们翻转的是后半部分 + var backhalf = reverse(midnode?.next); + //遍历两部分链表,判断值是否相等 + var p1 = head + var p2 = backhalf + while p2 != nil { + if p1?.val != p2?.val { + midnode?.next = reverse(backhalf) + return false + } + p1 = p1?.next + p2 = p2?.next + } + //还原链表并返回结果,这一步是需要注意的,我们不可以破坏初始结构,我们只是判断是否为回文, + //当然如果没有这一步也是可以AC,但是面试的时候题目要求可能会有这一条。 + midnode?.next = reverse(backhalf) + return true + } + //找到中点 + func searchmidnode(_ head: ListNode?) -> ListNode? { + var fast = head, slow = head + while fast?.next != nil && fast?.next?.next != nil { + fast = fast?.next?.next + slow = slow?.next + } + return slow + } + //翻转链表 + func reverse(_ slow: ListNode?) -> ListNode? { + var slow = slow + var low: ListNode? + var temp: ListNode? + while slow != nil { + temp = slow?.next + slow?.next = low + low = slow + slow = temp + } + return low + } +} +``` diff --git a/animation-simulation/链表篇/leetcode141环形链表.md b/animation-simulation/链表篇/leetcode141环形链表.md index b0e186f..5ae5ada 100644 --- a/animation-simulation/链表篇/leetcode141环形链表.md +++ b/animation-simulation/链表篇/leetcode141环形链表.md @@ -108,3 +108,20 @@ class Solution: return False ``` +Swift Code: + +```swift +class Solution { + func hasCycle(_ head: ListNode?) -> Bool { + var fast = head, slow = head + while fast != nil && fast?.next != nil { + fast = fast?.next?.next + slow = slow?.next + if fast === slow { + return true + } + } + return false + } +} +``` diff --git a/animation-simulation/链表篇/leetcode142环形链表2.md b/animation-simulation/链表篇/leetcode142环形链表2.md index e942a74..933eb40 100644 --- a/animation-simulation/链表篇/leetcode142环形链表2.md +++ b/animation-simulation/链表篇/leetcode142环形链表2.md @@ -132,8 +132,6 @@ class Solution: return head ``` - - ### 快慢指针 这个方法是比较巧妙的方法,但是不容易想到,也不太容易理解,利用快慢指针判断是否有环很容易,但是判断环的入口就没有那么容易,之前说过快慢指针肯定会在环内相遇,见下图。 @@ -275,3 +273,29 @@ class Solution: return slow ``` +Swift Code: + +```swift +class Solution { + func detectCycle(_ head: ListNode?) -> ListNode? { + // 快慢指针 + var fast = head, slow = head + while fast != nil && fast?.next != nil { + fast = fast?.next?.next + slow = slow?.next + // 相遇 + if fast === slow { + // 设置一个新的指针,从头节点出发,慢指针速度为1,所以可以使用慢指针从相遇点出发 + // 此处也可以不创新结点,直接将 fast = head + var newNode = head + while newNode !== slow { + slow = slow?.next + newNode = newNode?.next + } + return slow + } + } + return nil + } +} +``` \ No newline at end of file diff --git a/animation-simulation/链表篇/leetcode147对链表进行插入排序.md b/animation-simulation/链表篇/leetcode147对链表进行插入排序.md index 2a0b700..9bdd4e6 100644 --- a/animation-simulation/链表篇/leetcode147对链表进行插入排序.md +++ b/animation-simulation/链表篇/leetcode147对链表进行插入排序.md @@ -225,5 +225,41 @@ class Solution: return dummyNode.next ``` +Swift Code: - +```swift +class Solution { + func insertionSortList(_ head: ListNode?) -> ListNode? { + if head == nil && head?.next == nil { + return head + } + //哑节点 + var dummyNode = ListNode(-1) + dummyNode.next = head + //pre负责指向新元素,last 负责指向新元素的前一元素 + //判断是否需要执行插入操作 + var pre = head?.next + var last = head + while pre != nil { + //不需要插入到合适位置,则继续往下移动 + if last!.val <= pre!.val { + pre = pre?.next + last = last?.next + continue + } + //开始出发,查找新元素的合适位置 + var temphead = dummyNode + while temphead.next!.val <= pre!.val { + temphead = temphead.next! + } + //此时我们已经找到了合适位置,我们需要进行插入,大家可以画一画 + last?.next = pre?.next + pre?.next = temphead.next + temphead.next = pre + //继续往下移动 + pre = last?.next + } + return dummyNode.next + } +} +``` diff --git a/animation-simulation/链表篇/leetcode206反转链表.md b/animation-simulation/链表篇/leetcode206反转链表.md index 5885b41..e9aa1c8 100644 --- a/animation-simulation/链表篇/leetcode206反转链表.md +++ b/animation-simulation/链表篇/leetcode206反转链表.md @@ -138,6 +138,32 @@ class Solution: return low ``` +Swift Code: + +```swift +class Solution { + func reverseList(_ head: ListNode?) -> ListNode? { + // 边界条件 + if head == nil || head?.next == nil { + return head + } + var pro = head + var low: ListNode? + while pro != nil { + // 代表橙色指针 + var temp = pro + // 移动绿色指针 + pro = pro?.next + // 反转节点 + temp?.next = low + // 移动黄色指针 + low = temp + } + return low + } +} +``` + 上面的迭代写法是不是搞懂啦,现在还有一种递归写法,不是特别容易理解,刚开始刷题的同学,可以只看迭代解法。 @@ -227,6 +253,25 @@ class Solution: return pro ``` +Swift Code: + +```swift +class Solution { + func reverseList(_ head: ListNode?) -> ListNode? { + // 结束条件 + if head == nil || head?.next == nil { + return head + } + var pro = reverseList(head?.next) + // 将节点进行反转 + head?.next?.next = head + // 防止循环 + head?.next = nil + return pro + } +} +``` +
> 贡献者[@jaredliw](https://github.com/jaredliw)注: diff --git a/animation-simulation/链表篇/leetcode328奇偶链表.md b/animation-simulation/链表篇/leetcode328奇偶链表.md index 1b11c0e..6f7fc75 100644 --- a/animation-simulation/链表篇/leetcode328奇偶链表.md +++ b/animation-simulation/链表篇/leetcode328奇偶链表.md @@ -128,3 +128,27 @@ class Solution: return head ``` +Swift Code: + +```swift +class Solution { + func oddEvenList(_ head: ListNode?) -> ListNode? { + if head == nil || head?.next == nil { + return head + } + var odd = head + var even = head?.next + var evenHead = even + while odd?.next != nil && even?.next != nil { + //将偶数位合在一起,奇数位合在一起 + odd?.next = even?.next + odd = odd?.next + even?.next = odd?.next + even = even?.next + } + //链接 + odd?.next = evenHead + return head + } +} +``` \ No newline at end of file diff --git a/animation-simulation/链表篇/leetcode82删除排序链表中的重复元素II.md b/animation-simulation/链表篇/leetcode82删除排序链表中的重复元素II.md index 0768215..e786c73 100644 --- a/animation-simulation/链表篇/leetcode82删除排序链表中的重复元素II.md +++ b/animation-simulation/链表篇/leetcode82删除排序链表中的重复元素II.md @@ -165,3 +165,34 @@ class Solution: return dummy.next # 注意,这里传回的不是head,而是虚拟节点的下一个节点,head有可能已经换了 ``` +Swift Code: + +```swift +class Solution { + func deleteDuplicates(_ head: ListNode?) -> ListNode? { + // 侦察兵指针 + var pre = head + // 创建哑节点,接上head + var dummy = ListNode(-1) + dummy.next = head + // 跟随的指针 + var low:ListNode? = dummy + while pre != nil && pre?.next != nil { + if pre?.val == pre?.next?.val { + // 移动侦察兵指针直到找到与上一个不相同的元素 + while pre != nil && pre?.next != nil && pre?.val == pre?.next?.val { + pre = pre?.next + } + // while循环后,pre停留在最后一个重复的节点上 + pre = pre?.next + // 连上新节点 + low?.next = pre + } else { + pre = pre?.next + low = low?.next + } + } + return dummy.next // 注意,这里传回的不是head,而是虚拟节点的下一个节点,head有可能已经换了 + } +} +``` diff --git a/animation-simulation/链表篇/leetcode86分隔链表.md b/animation-simulation/链表篇/leetcode86分隔链表.md index 4147a75..b57511a 100644 --- a/animation-simulation/链表篇/leetcode86分隔链表.md +++ b/animation-simulation/链表篇/leetcode86分隔链表.md @@ -157,3 +157,34 @@ class Solution: return headsmall.next ``` +Swift Code: + +```swift +class Solution { + func partition(_ head: ListNode?, _ x: Int) -> ListNode? { + var pro = head + var big = ListNode(-1) + var small = ListNode(-1) + var headbig = big + var headsmall = small + //分 + while pro != nil { + //大于时,放到 big 链表上 + if pro!.val >= x { + big.next = pro + big = big.next! + //小于时,放到 small 链表上 + } else { + small.next = pro + small = small.next! + } + pro = pro?.next + } + //细节 + big.next = nil + //合 + small.next = headbig.next + return headsmall.next + } +} +``` diff --git a/animation-simulation/链表篇/leetcode92反转链表2.md b/animation-simulation/链表篇/leetcode92反转链表2.md index 93b90b6..136b6e0 100644 --- a/animation-simulation/链表篇/leetcode92反转链表2.md +++ b/animation-simulation/链表篇/leetcode92反转链表2.md @@ -218,3 +218,50 @@ class Solution: return low ``` +Swift Code: + +```swift +class Solution { + func reverseBetween(_ head: ListNode?, _ left: Int, _ right: Int) -> ListNode? { + // 虚拟头结点 + var temp = ListNode(-1) + temp.next = head + var pro:ListNode? = temp + // 来到 left 节点前的一个节点 + var i = 0 + for n in i.. ListNode? { + var low:ListNode? + var pro = head + while pro != nil { + var temp = pro + pro = pro?.next + temp?.next = low + low = temp + } + return low + } +} +``` \ No newline at end of file diff --git a/animation-simulation/链表篇/剑指Offer25合并两个排序的链表.md b/animation-simulation/链表篇/剑指Offer25合并两个排序的链表.md index cbe9b75..661b329 100644 --- a/animation-simulation/链表篇/剑指Offer25合并两个排序的链表.md +++ b/animation-simulation/链表篇/剑指Offer25合并两个排序的链表.md @@ -123,3 +123,27 @@ class Solution: return headtemp.next ``` +Swift Code: + +```swift +class Solution { + func mergeTwoLists(_ l1: ListNode?, _ l2: ListNode?) -> ListNode? { + var l1 = l1, l2 = l2 + var headpro: ListNode? = ListNode(-1) + var headtemp = headpro + while l1 != nil && l2 != nil { + //接上大的那个 + if l1!.val >= l2!.val { + headpro?.next = l2 + l2 = l2!.next + } else { + headpro?.next = l1 + l1 = l1!.next + } + headpro = headpro?.next + } + headpro?.next = l1 != nil ? l1 : l2 + return headtemp?.next + } +} +``` diff --git a/animation-simulation/链表篇/剑指Offer52两个链表的第一个公共节点.md b/animation-simulation/链表篇/剑指Offer52两个链表的第一个公共节点.md index c51ab29..a2576eb 100644 --- a/animation-simulation/链表篇/剑指Offer52两个链表的第一个公共节点.md +++ b/animation-simulation/链表篇/剑指Offer52两个链表的第一个公共节点.md @@ -135,6 +135,40 @@ class Solution: return tempb ``` +Swift Code: + +```swift +class Solution { + func getIntersectionNode(_ headA: ListNode?, _ headB: ListNode?) -> ListNode? { + var tempa = headA + var tempb = headB + var arr:Set = [] + //遍历链表A,将所有值都存到arr中 + while tempa != nil { + arr.insert(tempa!) + tempa = tempa?.next + } + //遍历列表B,如果发现某个结点已在arr中则直接返回该节点 + while tempb != nil { + if arr.contains(tempb!) { + return tempb + } + tempb = tempb?.next + } + //若上方没有返回,此刻tempb为null + return tempb + } +} +extension ListNode: Hashable, Equatable { + public func hash(into hasher: inout Hasher) { + hasher.combine(val) + hasher.combine(ObjectIdentifier(self)) + } + public static func ==(lhs: ListNode, rhs: ListNode) -> Bool { + return lhs === rhs + } +} +``` 下面这个方法比较巧妙,不是特别容易想到,大家可以自己实现一下,这个方法也是利用我们的双指针思想。 @@ -221,6 +255,25 @@ class Solution: return tempa # 返回tempb也行 ``` +Swift Code: + +```swift +class Solution { + func getIntersectionNode(_ headA: ListNode?, _ headB: ListNode?) -> ListNode? { + //定义两个节点 + var tempa = headA + var tempb = headB + //循环 + while tempa != tempb { + // 如果不为空就指针下移,为空就跳到另一链表的头部 + tempa = tempa != nil ? tempa?.next : headB + tempb = tempb != nil ? tempb?.next : headA + } + return tempa //返回tempb也行 + } +} +``` + 好啦,链表的题目就结束啦,希望大家能有所收获,下周就要更新新的题型啦,继续坚持,肯定会有收获的。
diff --git a/animation-simulation/链表篇/剑指offer22倒数第k个节点.md b/animation-simulation/链表篇/剑指offer22倒数第k个节点.md index 5dc879c..6d28871 100644 --- a/animation-simulation/链表篇/剑指offer22倒数第k个节点.md +++ b/animation-simulation/链表篇/剑指offer22倒数第k个节点.md @@ -136,3 +136,28 @@ class Solution: return after ``` +Swift Code: + +```swift +class Solution { + func getKthFromEnd(_ head: ListNode?, _ k: Int) -> ListNode? { + //特殊情况 + if head == nil { + return head + } + //初始化两个指针 + var pro = head, after = head + //先移动绿指针到指定位置 + for i in 0.. ListNode? { + var fast = head //快指针 + var slow = head //慢指针 + //循环条件,思考一下跳出循环的情况 + while fast != nil && fast?.next != nil { + fast = fast?.next?.next + slow = slow?.next + } + //返回slow指针指向的节点 + return slow + } +} +``` diff --git a/animation-simulation/链表篇/面试题 02.05. 链表求和.md b/animation-simulation/链表篇/面试题 02.05. 链表求和.md index 0865cb1..7ab8bb4 100644 --- a/animation-simulation/链表篇/面试题 02.05. 链表求和.md +++ b/animation-simulation/链表篇/面试题 02.05. 链表求和.md @@ -230,3 +230,42 @@ class Solution: return nList.next # 去除哑节点 ``` +Swift Code: + +```swift +class Solution { + func addTwoNumbers(_ l1: ListNode?, _ l2: ListNode?) -> ListNode? { + var l1 = l1, l2 = l2 + var nList = ListNode(-1) // 哑节点 + var tempnode = nList + // 用来保存进位值,初始化为0 + var summod = 0 + while l1 != nil || l2 != nil { + // 链表的节点值 + let l1num = l1?.val ?? 0 + let l2num = l2?.val ?? 0 + // 将链表的值和进位值相加,得到为返回链表的值 + var sum = l1num + l2num + summod + // 更新进位值,例18/10=1,9/10=0 + summod = sum / 10 + // 新节点保存的值,18%8=2,则添加2 + sum = sum % 10 + // 添加节点 + tempnode.next = ListNode(sum) + // 移动指针 + tempnode = tempnode.next! + if l1 != nil { + l1 = l1?.next + } + if l2 != nil { + l2 = l2?.next + } + } + // 最后根据进位值判断需不需要继续添加节点 + if (summod != 0) { + tempnode.next = ListNode(summod) + } + return nList.next //去除哑节点 + } +} +``` From 8920c2d83a56a28ed47df355698789b391e90b9a Mon Sep 17 00:00:00 2001 From: frank-tian Date: Mon, 19 Jul 2021 23:02:05 +0800 Subject: [PATCH 03/10] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=20Swift=20=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- animation-simulation/剑指offer/1的个数.md | 25 +++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/animation-simulation/剑指offer/1的个数.md b/animation-simulation/剑指offer/1的个数.md index 79c2f31..d3942c2 100644 --- a/animation-simulation/剑指offer/1的个数.md +++ b/animation-simulation/剑指offer/1的个数.md @@ -200,6 +200,31 @@ class Solution { } ``` +Swift Code: + +```swift +class Solution { + func countDigitOne(_ n: Int) -> Int { + var high = n, low = 0, cur = 0, count = 0, num = 1 + while high != 0 || cur != 0 { + cur = high % 10 + high /= 10 + //这里我们可以提出 high * num 因为我们发现无论为几,都含有它 + if cur == 0 { + count += high * num + } else if cur == 1 { + count += high * num + 1 + low + } else { + count += (high + 1) * num + } + low = cur * num + low + num *= 10 + } + return count + } +} +``` + 时间复杂度 : O(logn) 空间复杂度 O(1) From 9116bc63ce0677d71a6e6580053bab5bb94cb9c3 Mon Sep 17 00:00:00 2001 From: frank-tian Date: Mon, 19 Jul 2021 23:13:17 +0800 Subject: [PATCH 04/10] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=20Swift=20=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- animation-simulation/二叉树/二叉树基础.md | 36 +++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/animation-simulation/二叉树/二叉树基础.md b/animation-simulation/二叉树/二叉树基础.md index 17fca26..01a6f2c 100644 --- a/animation-simulation/二叉树/二叉树基础.md +++ b/animation-simulation/二叉树/二叉树基础.md @@ -406,6 +406,42 @@ public: }; ``` +Swift Code: + +```swift +class Solution { + func levelOrder(_ root: TreeNode?) -> [[Int]] { + var res:[[Int]] = [] + guard root != nil else { + return res + } + var queue:[TreeNode?] = [] + queue.append(root!) + + while !queue.isEmpty { + let size = queue.count + var list:[Int] = [] + + for i in 0.. Date: Mon, 19 Jul 2021 23:22:39 +0800 Subject: [PATCH 05/10] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=20Swift=20=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../二叉树/二叉树的前序遍历(栈).md | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/animation-simulation/二叉树/二叉树的前序遍历(栈).md b/animation-simulation/二叉树/二叉树的前序遍历(栈).md index e81749b..90fea79 100644 --- a/animation-simulation/二叉树/二叉树的前序遍历(栈).md +++ b/animation-simulation/二叉树/二叉树的前序遍历(栈).md @@ -67,3 +67,32 @@ class Solution { } ``` +Swift Code: + +```swift +class Solution { + + func preorderTraversal(_ root: TreeNode?) -> [Int] { + var list:[Int] = [] + var stack:[TreeNode] = [] + + guard root != nil else { + return list + } + stack.append(root!) + while !stack.isEmpty { + let temp = stack.popLast() + if let right = temp?.right { + stack.append(right) + } + if let left = temp?.left { + stack.append(left) + } + //这里也可以放到前面 + list.append((temp?.val)!) + } + return list + } +} +``` + From ef44b3f3be86dcb2207d861dfb13d3904a35affb Mon Sep 17 00:00:00 2001 From: frank-tian Date: Mon, 19 Jul 2021 23:32:21 +0800 Subject: [PATCH 06/10] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=20Swift=20=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../二叉树/二叉树的前序遍历(Morris).md | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/animation-simulation/二叉树/二叉树的前序遍历(Morris).md b/animation-simulation/二叉树/二叉树的前序遍历(Morris).md index a6722b8..95a141f 100644 --- a/animation-simulation/二叉树/二叉树的前序遍历(Morris).md +++ b/animation-simulation/二叉树/二叉树的前序遍历(Morris).md @@ -103,4 +103,41 @@ class Solution { } ``` +Swift Code: + +```swift +class Solution { + func preorderTraversal(_ root: TreeNode?) -> [Int] { + var list:[Int] = [] + guard root != nil else { + return list + } + var p1 = root, p2: TreeNode? + while p1 != nil { + p2 = p1!.left + if p2 != nil { + //找到左子树的最右叶子节点 + while p2!.right != nil && p2!.right !== p1 { + p2 = p2!.right + } + //添加 right 指针,对应 right 指针为 null 的情况 + if p2!.right == nil { + list.append(p1!.val) + p2!.right = p1 + p1 = p1!.left + continue + } + //对应 right 指针存在的情况,则去掉 right 指针 + p2!.right = nil + } else { + list.append(p1!.val) + } + //移动 p1 + p1 = p1!.right + } + return list + } +} +``` + 好啦,今天就看到这里吧,咱们下期见! \ No newline at end of file From 7572d7c2f75745e9b59647e89910b9107d72f410 Mon Sep 17 00:00:00 2001 From: frank-tian Date: Mon, 19 Jul 2021 23:39:19 +0800 Subject: [PATCH 07/10] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=20Swift=20=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../二叉树/二叉树中序遍历(迭代).md | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/animation-simulation/二叉树/二叉树中序遍历(迭代).md b/animation-simulation/二叉树/二叉树中序遍历(迭代).md index adbec99..8dd15e7 100644 --- a/animation-simulation/二叉树/二叉树中序遍历(迭代).md +++ b/animation-simulation/二叉树/二叉树中序遍历(迭代).md @@ -51,5 +51,32 @@ class Solution { } ``` +Swift Code: + +```swift +class Solution { + func inorderTraversal(_ root: TreeNode?) -> [Int] { + var arr:[Int] = [] + var cur = root + var stack:[TreeNode] = [] + + while !stack.isEmpty || cur != nil { + //找到当前应该遍历的那个节点 + while cur != nil { + stack.append(cur!) + cur = cur!.left + } + //此时指针指向空,也就是没有左子节点,则开始执行出栈操作 + if let temp = stack.popLast() { + arr.append(temp.val) + //指向右子节点 + cur = temp.right + } + } + return arr + } +} +``` + ### From acc662b89ae79f1d7ae6ef90d964fd51c78ee238 Mon Sep 17 00:00:00 2001 From: frank-tian Date: Mon, 19 Jul 2021 23:49:48 +0800 Subject: [PATCH 08/10] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=20Swift=20=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../二叉树/二叉树的后续遍历 (迭代).md | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/animation-simulation/二叉树/二叉树的后续遍历 (迭代).md b/animation-simulation/二叉树/二叉树的后续遍历 (迭代).md index f9b4265..5a8bac8 100644 --- a/animation-simulation/二叉树/二叉树的后续遍历 (迭代).md +++ b/animation-simulation/二叉树/二叉树的后续遍历 (迭代).md @@ -71,6 +71,39 @@ class Solution { } ``` +Swift Code: + +```swift +class Solution { + func postorderTraversal(_ root: TreeNode?) -> [Int] { + var list:[Int] = [] + var stack:[TreeNode] = [] + var cur = root, preNode: TreeNode? + while !stack.isEmpty || cur != nil { + //和之前写的中序一致 + while cur != nil { + stack.append(cur!) + cur = cur!.left + } + //1.出栈,可以想一下,这一步的原因。 + cur = stack.popLast() + //2.if 里的判断语句有什么含义? + if cur!.right === nil || cur!.right === preNode { + list.append(cur!.val) + //更新下 preNode,也就是定位住上一个访问节点。 + preNode = cur + cur = nil + } else { + //3.再次压入栈,和上面那条 1 的关系? + stack.append(cur!) + cur = cur!.right + } + } + return list + } +} +``` + 当然也可以修改下代码逻辑将 `cur = stack.pop()` 改成 `cur = stack.peek()`,下面再修改一两行代码也可以实现,这里这样写是方便动画模拟,大家可以随意发挥。 时间复杂度 O(n), 空间复杂度O(n) From da6ec4e14f99add79e5a04e41888192d874e65f4 Mon Sep 17 00:00:00 2001 From: frank-tian Date: Mon, 19 Jul 2021 23:54:09 +0800 Subject: [PATCH 09/10] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=20Swift=20=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../二叉树/二叉树中序遍历(Morris).md | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/animation-simulation/二叉树/二叉树中序遍历(Morris).md b/animation-simulation/二叉树/二叉树中序遍历(Morris).md index 3c6ff79..d67ede6 100644 --- a/animation-simulation/二叉树/二叉树中序遍历(Morris).md +++ b/animation-simulation/二叉树/二叉树中序遍历(Morris).md @@ -102,3 +102,34 @@ class Solution { } ``` +Swift Code: + +```swift +class Solution { + func inorderTraversal(_ root: TreeNode?) -> [Int] { + var list:[Int] = [] + guard root != nil else { + return list + } + var p1 = root, p2: TreeNode? + while p1 != nil { + p2 = p1!.left + if p2 != nil { + while p2!.right != nil && p2!.right !== p1 { + p2 = p2!.right + } + if p2!.right == nil { + p2!.right = p1 + p1 = p1!.left + continue + } else { + p2!.right = nil + } + } + list.append(p1!.val) + p1 = p1!.right + } + return list + } +} +``` From 37b2a2a12b594de1e7951afcf242642149fc79ff Mon Sep 17 00:00:00 2001 From: frank-tian Date: Tue, 20 Jul 2021 00:00:44 +0800 Subject: [PATCH 10/10] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=20Swift=20=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../二叉树/二叉树的后续遍历(Morris).md | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/animation-simulation/二叉树/二叉树的后续遍历(Morris).md b/animation-simulation/二叉树/二叉树的后续遍历(Morris).md index 4cd9ce3..12f55ff 100644 --- a/animation-simulation/二叉树/二叉树的后续遍历(Morris).md +++ b/animation-simulation/二叉树/二叉树的后续遍历(Morris).md @@ -116,6 +116,62 @@ class Solution { } ``` +Swift Code: + +```swift +class Solution { + var list:[Int] = [] + func postorderTraversal(_ root: TreeNode?) -> [Int] { + guard root != nil else { + return list + } + var p1 = root, p2: TreeNode? + while p1 != nil { + p2 = p1!.left + if p2 != nil { + while p2!.right != nil && p2!.right !== p1 { + p2 = p2!.right + } + if p2!.right == nil { + p2!.right = p1 + p1 = p1!.left + continue + } else { + p2!.right = nil + postMorris(p1!.left) + } + } + p1 = p1!.right + } + //以根节点为起点的链表 + postMorris(root!) + return list + } + + func postMorris(_ root: TreeNode?) { + let reverseNode = reverseList(root) + //从后往前遍历 + var cur = reverseNode + while cur != nil { + list.append(cur!.val) + cur = cur!.right + } + reverseList(reverseNode) + } + + func reverseList(_ head: TreeNode?) -> TreeNode? { + var cur = head, pre: TreeNode? + while cur != nil { + let next = cur?.right + cur?.right = pre + pre = cur + cur = next + } + return pre + } +} +``` + 时间复杂度 O(n)空间复杂度 O(1) 总结:后序遍历比起前序和中序稍微复杂了一些,所以我们解题的时候,需要好好注意一下,迭代法的核心是利用一个指针来定位我们上一个遍历的节点,Morris 的核心是,将某节点的右子节点,看成是一条链表,进行反向遍历。