Day2.1 剑指 Offer 06. 从尾到头打印链表
输入一个链表的头节点,从尾到头 反过来返回每个节点的值(用数组返回)
eg:
输入:head = [1,3,2]
输出:[2,3,1]
方案1: 直接向List中倒着插入
建立一个list
从前到后遍历链表 ,将值从list的头一一插入 【用了List内置函数】
时间复杂度:n
空间复杂度: n
class Solution:
def reversePrint(self, head: ListNode) -> List[int]:
re_list = []
# 遍历链表 将值从头一个个插入list
while(head):
# head 后面也是带着val
if head != None:
re_list.insert(0,head.val) # TODO: 耗时
head = head.next
return re_list
执行用时:44 ms, 在所有 Python3 提交中击败了51.37%的用户
内存消耗:16.3 MB, 在所有 Python3 提交中击败了70.68%的用户
方案2:反转链表后打印
时间:n
空间:由反转的算法决定
class Solution:
def reversePrint(self, head: ListNode) -> List[int]:
re_list = []
# 反转链表
head = self.reverse(head)
# 将链表打印到list
while(head):
re_list.append(head.val)
head = head.next
return re_list
def reverse(self,head):
pre = None # 不能是 ListNode() 不然就会带着这个节点
nxt = ListNode()
while(head):
nxt = head.next # 保护断点
head.next = pre # 切开断点
# pre head 向前移动一个单位
pre = head
head = nxt
return pre
执行用时:36 ms, 在所有 Python3 提交中击败了82.00%的用户
内存消耗:16.3 MB, 在所有 Python3 提交中击败了51.57%的用户
时间快了很多,空间感觉基本没变,是中间变量占位置了吗 ?
Day2.2 剑指 Offer 24. 反转链表
有意思了 这个题就是2.1的第二种解法用到的一个部分
其实这个题已经是第三次做了
但是感觉还是不熟练
方案1: 迭代
其实就是:前继,后缀 指针的移动,主要的核心点有三个部分
- while循环的判别条件: 用head,还是head.next —- None节点索引next会出错 所以用前者
- pre , head, nxt 的轮回,旧值移出,新值就要移动入
return的是什么 head还是pre? 因为pre是跟着链到最后的男人。而且不是空,所以是pre
class Solution:
def reverseList(self, head: ListNode) -> ListNode:
pre = None
while(head):
nxt = head.next
head.next = pre
pre = head
head = nxt
return pre
执行用时:44 ms, 在所有 Python3 提交中击败了26.46%的用户
内存消耗:15.5 MB, 在所有 Python3 提交中击败了69.03%的用户
但是结果不太好
后面补充一个好一些的结果
减少一个中间变量,可以一句遍历:
class Solution:
def reverseList(self, head: ListNode) -> ListNode:
pre = None
while(head):
head.next,pre, head = pre,head,head.next
return pre
执行用时:40 ms, 在所有 Python3 提交中击败了45.96%的用户
内存消耗:15.5 MB, 在所有 Python3 提交中击败了73.95%的用户
稍稍好一点点
当然还可以用递归的方法实现: 后序遍历
方案2:递归
参考的labuladong的算法小抄中284页 — 秀操作之反转整个链表
class Solution:
def reverseList(self, head: ListNode) -> ListNode:
# Step1: base case
if (head == None or head.next == None ):
return head
# Step2: recursion -- 深度优先
last = self.reverseList(head.next)
# Step3: deal end
head.next.next = head
head.next = None
return last
我的理解:
Step2处的 last 处递归下去只为了拿到 Step1 处的底,也就是最后一个节点
在递归压栈回传的时候,head.next 后的链表一个个反转了过来
【假设只有两个节点 你寻思一下是不是可以反转】
在最后,last成为了新链表的头,head.next 成为了新链表的尾。
还需要将head排到head.next的后面
而且最后head后面要以None收尾
即
head.next.next = head
head.next = None
执行用时:32 ms, 在所有 Python3 提交中击败了86.59%的用户
内存消耗:19.6 MB, 在所有 Python3 提交中击败了12.89%的用户
其实递归也没有那么香。
当压栈数量很大的时候,非常不利
Day2.3 剑指 Offer 35. 复杂链表的复制
复制一个复杂链表。
在复杂链表中,每个节点除了有一个 next 指针指向下一个节点,还有一个 random 指针指向链表中的任意节点或者 null
md ,中等题就这么复杂吗?mmp
题解都不想看 mmp 走了走了 下次再看 — 直接往后走