题目:输入一个链表的头节点,按链表值从尾到头的顺序返回一个ArrayList。
样例
输入:[2, 3, 5]
返回:[5, 3, 2]
首先想到反转链表,然后就可以从头到尾的输出了,但是这样会改变原来链表的结构,而通常打印是只读操作,这里假设这道题也不允许修改链表结构。
思路1:借助数组反转
从头到尾将链表打印到数组中,将数组反转输出。
复杂度分析
时间复杂度:O(n),因为 遍历一趟数组,以及reverse()的时间复杂度均为 O(n),因此最终时间复杂度也为 O(n)。
空间复杂度:O(n),使用了额外的数组。
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution(object):
def printListReversingly(self, head):
"""
:type head: ListNode
:rtype: List[int]
"""
if not head: # 空链表测试
return []
ls = []
cur = head #
while cur is not None:
ls.append(cur.val) #正序存入,也可倒序ls.insert(0,cur.val)
cur = cur.next
return ls[::-1] # 倒序输出,还可以:
# ls.reverse
# return ls
注:
Python List 的 insert()
方法用于将指定对象插入列表的指定位置。
list.insert(index, obj)
index
– 对象 obj 需要插入的索引位置。
obj
– 要插入列表中的对象。
【1】一定注意是小括号insert( ) 不是. 以及[ ] , 每次都错在这里!
【2】 正序存入可以append,可以insert(val),而倒序存入是ls.insert(0, value),
【3】append的是.val,倒序输出除了[::-1]还可以 ls.reverse(),return ls,但是不可以直接 return ls.reverse()
思路2:栈
这个问题肯定要遍历链表,遍历的顺序是从头到尾,但输出是从尾到头,
后进先出,符合栈的特点。
因此可以在遍历时,把每个节点都压入栈,遍历完整个链表之后再从栈顶开始输出,即为逆序。
class Solution(object):
def reversePrint(self, head):
"""
:type head: ListNode
:rtype: List[int]
"""
if not head:
return []
cur=head
stack,res=[],[]
while cur:
stack.append(cur.val) # 这里如果存cur,后面res就要存 stack.pop().val
cur=cur.next
while stack:
res.append(stack.pop())
return res
复杂度分析
时间复杂度:O(n),因为push的时间复杂度为 O(n),pop 的时间复杂度为 O(n)。
空间复杂度:O(n),使用了额外的 数组 和 栈。
思路3:递归
已经想到了栈,而递归本质上就是一个栈结构, 因此也可以用递归来实现。
每访问一个节点的时候,先递归输它后面的节点,再输出该节点自身。
当链表非常长的时候,会导致函数调用的层级很深,就有可能导致函数调用栈溢出,因此用栈基于循环实现的鲁棒性更好。
class Solution(object):
def reversePrint(self, head):
res=self.recursive(head)
return res
def recursive(self,node):
if node:
return self.recursive(node.next)+[node.val]
else:
return []
###### 另一种写法
class Solution(object):
def reversePrint(self, head):
if not head:
return []
return self.reversePrint(head.next)+[head.val]
复杂度分析
时间复杂度:O(n),递归 n次,时间复杂度为 O(n),递归函数中的操作时间复杂度为 O(1),总时间复杂度为 O(n)xO(1)=O(n)。
空间复杂度:O(n),递归将占用链表长度的栈空间。