mirror of
https://github.com/chefyuan/algorithm-base.git
synced 2024-12-26 20:36:18 +00:00
为链表篇 增加 Swift 实现
This commit is contained in:
parent
a16c030b44
commit
7b55df11dc
@ -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
|
||||
}
|
||||
}
|
||||
```
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
```
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
```
|
@ -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
|
||||
}
|
||||
}
|
||||
```
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
<br/>
|
||||
|
||||
> 贡献者[@jaredliw](https://github.com/jaredliw)注:
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
```
|
@ -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有可能已经换了
|
||||
}
|
||||
}
|
||||
```
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
```
|
||||
|
@ -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..<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
|
||||
}
|
||||
}
|
||||
```
|
@ -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
|
||||
}
|
||||
}
|
||||
```
|
||||
|
@ -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<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也行
|
||||
```
|
||||
|
||||
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/>
|
||||
|
@ -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..<k-1 {
|
||||
pro = pro?.next
|
||||
}
|
||||
//两个指针同时移动
|
||||
while pro?.next != nil {
|
||||
pro = pro?.next
|
||||
after = after?.next
|
||||
}
|
||||
//返回倒数第k个节点
|
||||
return after
|
||||
}
|
||||
}
|
||||
```
|
||||
|
@ -118,3 +118,20 @@ class Solution:
|
||||
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
|
||||
}
|
||||
}
|
||||
```
|
||||
|
@ -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 //去除哑节点
|
||||
}
|
||||
}
|
||||
```
|
||||
|
Loading…
Reference in New Issue
Block a user