携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第6天,点击查看活动详情 。如果哪里写的不对,请大家评论批评。
希望往后的日子,可以每天坚持一个算法
题目
给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。
例子1
输入: head = [1,2,3,4,5]
输出: [5,4,3,2,1]
例子2
输入: head = [1,2]
输出: [2,1]
例子3
输入: head = []
输出: []
分析
1、这是一个链表,只能从head开始。 2、想要反转就需要把0.next=nil,1.next=0 3、需要一个节点变量记录当前的位置,当需要0.next=nil之前,还需要记录1的位置,必须先记录再断开。 4、还需一个节点来记录已经反转的部分链表
图解
- 首先画出一个链表,用
cur来记录当前的节点 - 然后使用
next来临时记录下一个节点next = cur.next(当cur断开之后,临时当做头节点使用) - 这时候cur就可以断开链表了,反转后他是最后一位,所以
cur.next = nil
这里要注意,一会
cur.next = nil有变化
- 这时候我们需要
pre来保存着已经反转的链表,作为反转之后链表的头结点,下一步就可以处理后面的节点了,cur就变成了cur = next - 这时候我们完成了第一个节点的拆分
- 下面拆分第二个节点,来看看怎么操作
- 几乎重复2-5步骤,这个时候
cur指向了2,next继续记录下一个节点next = cur.next(当cur断开之后,临时当做头节点使用) - 这时候cur就可以断开链表了,下一步需要去组装反转之后的链表
注意的点来了,这时候
cur指向的是2,需求是2.next -> 1所以cur.next = pre问题来了,我们大概率需要循环2-5的过程,第一步1的时候
cur.next = nil和第二部的cur.next = pre的不一样,怎么办?你是不是发现,第一步的时候
pre实际上是nil的,那么实际想第一步也可以cur.next = pre
- 之后依然需要
pre来保存着已经反转的链表,作为反转之后链表的头结点,下一步就可以处理后面的节点了,cur就变成了cur = next - 这时候我们完成了第一个节点的拆分
- 之后就按照2-5一直循环下去,一直到
cur == nil
代码
class Solution {
func reverseList(_ head: ListNode?) -> ListNode? {
// 链表是否成立
if head == nil || head?.next == nil {
return head
}
// 反转之后链表的头结点
var pre : ListNode?
// 当前节点的位置
var cur : ListNode? = head
// 临时记录下一个节点,作为临时的头节点
var next : ListNode?
// 如果当前节点不为nil,一直循环下去
while cur != nil {
// 使用临时节点,记录下一个节点,保证前面节点断开不会丢失
next = cur?.next
// 当前节点的next指向,已经反转链表的头节点
cur?.next = pre
// 当前节点就成为了,已反转链表的头节点
pre = cur
// 当前节点向后移位
cur = next
}
// 返回已反转链表的头节点
return pre!
}
}