1.题目描述
2.解题思路(Python版)
方法一:迭代
思路:
链表反转即将每个结点的指针从向后变为向前,所以最简单的办法就是遍历原始链表,将遇到的结点指针一一逆向即可,但这样做有一个缺陷,如果我们将当前结点原本向后的指针修改为指向前一个结点的指针,那将会造成链表断裂,从后一个结点开始的链表信息丢失。为了弥补这个缺陷,我们应该额外存储下一个结点。具体实现思路如下:
1.设置两个指针,一个表示上一个结点的指针(pre,初始值为空),一个表示当前结点的指针(cur);
2.遍历整个链表,每访问一个结点,先将下一个结点的信息存储到temp中,然后断开当前结点与后面结点的指针,将当前结点指向前一个结点;
3.轮换当前指针与上一个指针,让它们分别指向下一个结点及下一个结点的前序结点,完成一次迭代;
4.迭代的结束条件:cur指向的下一个结点为空,即已遍历到原始链表的尾结点处。
参考代码:
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
#
# @param head ListNode类
# @return ListNode类
#
class Solution:
def ReverseList(self , head: ListNode) -> ListNode:
# write code here
pre = None #若原始链表为空链表,则直接输出一个空链表
cur = head #存储头结点
while cur:
temp = cur.next #将当前结点的下一个结点保存下来,避免链表断裂后丢失后续结点
cur.next = pre #原链表头结点变为反转后的尾结点,其next域变为空
pre = cur #前一个结点更新为当前结点
cur = temp #指针移动到下一个结点上
return pre
在实现过程中存在一个疑问:为什么pre最后输出的不是原始链表的尾结点(即反转后的链表的头结点),而是整个反转后的链表,询问GPT老师后得到以下回答:在链表中,结点不仅仅包含一个值,还包含一个指向下一个结点的引用。因此,当你返回链表的头结点时,实际上你返回的是一个包含整个链表结构的结点。
复杂度:
时间复杂度O(N):遍历链表一次,N是链表的长度;
空间复杂度O(1):常数级变量,无额外辅助空间使用。
方法二:递归
思路:
1.递归条件:逆转当前结点与其后整个子链表之间的指针,然后继续对子链表做上述操作;
2.基线条件(递归结束条件):当前处理的链表头结点为空,或头结点的Next域为空
参考代码:
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
#
# @param head ListNode类
# @return ListNode类
#
class Solution:
def ReverseList(self , head: ListNode) -> ListNode:
# write code here
if head is None or head.next is None: #基线条件
return head
newHead = self.ReverseList(head.next) #对子链表做反转
head.next.next = head #逆转当前节点
head.next = None #尾结点设为空结点
return newHead
复杂度:
时间复杂度O(N):遍历链表一次,N是链表的长度;
空间复杂度O(N):递归栈深度为链表长度N,相较于迭代方法,花费更多空间。
除以上两种方法外,还可以借助JZ6中的方法,将链表从尾到头打印后放置在数组中,再将数组转为链表即可。使用如下方法可将数组转换为链表:
def createNode(nums):
if len(nums) == 0:
return None
head = ListNode(nums[0])
cur = head
for i in range(1, len(nums)):
cur.next = ListNode(nums[i])
cur = cur.next
return head