原题链接:LeetCode 206 反转链表
反转一个单链表。
就直接按照进阶的要求自己吧。
解法一
迭代法+双指针
def reverseList(head):
if not head:
return None
pre, cur = head, head.next
while cur:
# temp 为临时变量 用于保存下一个cur需要更新的节点
temp = cur.next
cur.next = pre
pre = cur
cur = temp
head.next = None
return pre
在评论区看到一个有意思的写法,只是较为巧妙地利用了python的赋值语句,举例说明一下:如果原链表为1->2->3->4->None
,很明显,等号右边为(1, None, 2)
,依次执行赋值:rev = 1
,反转:rev.next = rev
,此时就变为1->None
,赋值:p = p.next
,此时p
指向的是2
,需要注意的是由于并行赋值的原因,p
节点未受到影响,这里2->3->4->None
依然存在。然后就依次迭代进行,直到p
节点为空:
def reverseList(head):
p, rev = head, None
while p:
# 这是一种并行赋值
# 等号右边会被当做一个元组(tuple)打包
# 然后解包(unpack)给等号右边
rev, rev.next, p = p, rev, p.next
return rev
解法二
递归法
递归相对而言不好理解的就是,我们在递归原链表时,应当返回递归最深处,也就是最后一个节点作为反转链表的头。这也就决定了该节点需要一直往上回溯到程序结束的地方。相应的,递归程序的主体部分就是用来反转两个节点。需要注意的是,我们返回的结果需要保证原链表的head
节点的next
应为None
,对此,也在递归主体部分完成。说起来相对比较绕,看看程序,画画图应该能大体理解。
def reverseList(head):
# 递归结束 返回最后一个节点作为结果的头节点
if not head or not head.next:
return head
node = reverseList(head.next)
# 反转
head.next.next = head
# 处理None
head.next = None
return node
设n为节点个数。两种解法的时间复杂度都为O(n),因为都仅仅遍历了所有的节点一次。而迭代法只用到了常数级别的空间复杂度,递归的空间复杂度为O(n)。
note:
几个月前,自己刚开始学习归并排序算法的时候(递归),不夸张地说,一个下午都快磨完了。尽管本质的东西依然没能析透,但现在也有所理解。无他,唯手熟尔…道阻且长,奥利给!!!