为链表篇 增加 Swift 实现

This commit is contained in:
frank-tian 2021-07-17 22:28:06 +08:00
parent a16c030b44
commit 7b55df11dc
14 changed files with 499 additions and 3 deletions

View File

@ -145,6 +145,35 @@ class Solution:
return True 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 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
}
}
```

View File

@ -108,3 +108,20 @@ class Solution:
return False 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
}
}
```

View File

@ -132,8 +132,6 @@ class Solution:
return head return head
``` ```
### 快慢指针 ### 快慢指针
这个方法是比较巧妙的方法但是不容易想到也不太容易理解利用快慢指针判断是否有环很容易但是判断环的入口就没有那么容易之前说过快慢指针肯定会在环内相遇见下图 这个方法是比较巧妙的方法但是不容易想到也不太容易理解利用快慢指针判断是否有环很容易但是判断环的入口就没有那么容易之前说过快慢指针肯定会在环内相遇见下图
@ -275,3 +273,29 @@ class Solution:
return slow 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
}
}
```

View File

@ -225,5 +225,41 @@ class Solution:
return dummyNode.next 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
}
}
```

View File

@ -138,6 +138,32 @@ class Solution:
return low 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 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
}
}
```
<br/> <br/>
> 贡献者[@jaredliw](https://github.com/jaredliw) > 贡献者[@jaredliw](https://github.com/jaredliw)

View File

@ -128,3 +128,27 @@ class Solution:
return head 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
}
}
```

View File

@ -165,3 +165,34 @@ class Solution:
return dummy.next # 注意这里传回的不是head而是虚拟节点的下一个节点head有可能已经换了 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有可能已经换了
}
}
```

View File

@ -157,3 +157,34 @@ class Solution:
return headsmall.next 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
}
}
```

View File

@ -218,3 +218,50 @@ class Solution:
return low 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..<left - 1 {
pro = pro?.next
i += 1
}
// 保存 left 节点前的一个节点
var leftNode = pro
// 来到 right 节点
for n in i..<right {
pro = pro?.next
}
// 保存 right 节点后的一个节点
var rightNode:ListNode? = pro?.next
// 切断链表
pro?.next = nil // 切断 right 后的部分
var newHead:ListNode? = leftNode?.next // 保存 left 节点
leftNode?.next = nil // 切断 left 前的部分
// 反转
leftNode?.next = reverse(newHead)
// 重新接头
newHead?.next = rightNode
return temp.next
}
// 和反转链表1代码一致
func reverse(_ head: ListNode?) -> ListNode? {
var low:ListNode?
var pro = head
while pro != nil {
var temp = pro
pro = pro?.next
temp?.next = low
low = temp
}
return low
}
}
```

View File

@ -123,3 +123,27 @@ class Solution:
return headtemp.next 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
}
}
```

View File

@ -135,6 +135,40 @@ class Solution:
return tempb return tempb
``` ```
Swift Code
```swift
class Solution {
func getIntersectionNode(_ headA: ListNode?, _ headB: ListNode?) -> ListNode? {
var tempa = headA
var tempb = headB
var arr:Set<ListNode> = []
//遍历链表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也行 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也行
}
}
```
好啦链表的题目就结束啦希望大家能有所收获下周就要更新新的题型啦继续坚持肯定会有收获的 好啦链表的题目就结束啦希望大家能有所收获下周就要更新新的题型啦继续坚持肯定会有收获的
<br/> <br/>

View File

@ -136,3 +136,28 @@ class Solution:
return after 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..<k-1 {
pro = pro?.next
}
//两个指针同时移动
while pro?.next != nil {
pro = pro?.next
after = after?.next
}
//返回倒数第k个节点
return after
}
}
```

View File

@ -118,3 +118,20 @@ class Solution:
return slow return slow
``` ```
Swift Code
```swift
class Solution {
func middleNode(_ head: ListNode?) -> ListNode? {
var fast = head //快指针
var slow = head //慢指针
//循环条件思考一下跳出循环的情况
while fast != nil && fast?.next != nil {
fast = fast?.next?.next
slow = slow?.next
}
//返回slow指针指向的节点
return slow
}
}
```

View File

@ -230,3 +230,42 @@ class Solution:
return nList.next # 去除哑节点 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=19/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 //去除哑节点
}
}
```