题目描述:
反转一个单链表。
示例:
输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL
进阶:
你可以迭代或递归地反转链表。你能否用两种方法解决这道题?
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/reverse-linked-list
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
解题思路:
思路1:迭代
假设有链表1->2->3->4->5->None,
反转后得None<-1<-2<-3<-4<-5
这个过程相当于,在遍历链表的过程中,每一个当前节点的next,由原来的指向下一个改为指向前一个。
举例来说:
如果当前节点是2,那么他的下一个节点是3,前一个节点是1
也就是,由原来的2->3改为了2->1。这个过程看似简单,但是实际操作时,需要辅助变量。
方便分析,以1->2->3->None为例:
- 当1为当前节点时,1需要指向它的前一个节点,这里指向None。所以,完成这个过程后,此时链表实际上是:
None<-1,2->3->None
显然,如果想继续遍历链表,需要将当前节点cur由1变为2,但是因为1的next已经指向None,无法指向2。这时就需要通过赋值的方法将当前节点指定为2。这需要先将节点2获得并且存储,然后在将其赋给cur。节点2在反转操作之前,可以通过cur.next获得。在这里,可以将变量设为nextNode。则在nextNode = cur.next。这样在一系列反转后,将cur = nextNode,就可以达到继续遍历的目的。 - 继续遍历,当cur为节点2时,此时链表依然是None<-1,2->3->None,这时的操作是2的下一个节点需要指向1,而1和2之间没有联系,依然需要通过赋值来实现。这就需要在上一步过程中,有一个变量可以存储节点1。用prevNode存储,则在上一步中,prevNode = cur,即当前节点就是下一个节点的前置节点。
有了nextNode和prevNode,整个过程就可以描述为:
- 将下一个节点存储:nextNode = cur.next
- 将当前节点的下一个节点指向前置节点:cur.next = prevNode
- 将当前节点存为下一步的前置节点:prevNode = cur
- 将当前节点设为下一个节点,开始新一轮反转:cur = nextNode
具体代码如下:
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def reverseList(self, head: ListNode) -> ListNode:
if not head or not head.next:
return head
cur = head
prevNode = None
nextNode = None
while cur:
nextNode = cur.next
cur.next = prevNode
prevNode = cur
cur = nextNode
return prevNode
运行结果:
时间复杂度:O(n),假设n是列表的长度,时间复杂度是 O(n)。
空间复杂度:O(1)。
思路2:递归
假设1->2->3->4->5,如果其中部分链表已经实现反转,比如:1->2->3<-4<-5,3->None。那么,当实现2和3之间的反转,只需要完成让3的next指向2,2的next指向None。
head_r = f(),表示子链表已经实现反转
cur.next.next = cur
cur.next = None
代码如下:
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
fake_head = ListNode(-1)
def reverseList(self, head: ListNode) -> ListNode:
if not head or not head.next:
return head
head_r = self.reverseList(head.next)
head.next.next = head
head.next = None
return head_r
运行结果:
时间复杂度:O(n),假设 nn 是列表的长度,那么时间复杂度为 O(n)。
空间复杂度:O(n),由于使用递归,将会使用隐式栈空间。递归深度可能会达到n层。
总结:
这道题将链表反转理解成1逐渐向后,每次下一个节点都添加到head,就麻烦了。比如,1->2->3,1到2后,2到头,然后1到3后,3到头。这种思路的迭代会变得十分复杂。这道题递归的思路不是最优解,但是递归的思路很锻炼逻辑思维能力。