From 7b55df11dcbe8cb38ccb44a51e3803da8317c297 Mon Sep 17 00:00:00 2001 From: frank-tian Date: Sat, 17 Jul 2021 22:28:06 +0800 Subject: [PATCH] =?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 //去除哑节点 + } +} +```