链表
offer6——从尾到头打印链表
输入一个链表的头节点,从尾到头反过来返回每个节点的值(用数组返回)。
解题思路
利用递归: 先走至链表末端,回溯时依次将节点值加入列表 ,这样就可以实现链表值的倒序输出。
算法流程
- 递推阶段: 每次传入 head.next ,以 head == NULL(即走过链表尾部节点)为递归终止条件,此时返回空列表 [] 。
- 回溯阶段: 利用 Python 语言特性,递归回溯时每次返回 当前 list + 当前节点值 [head.val] ,即可实现节点的倒序输出。
Python代码如下
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def reversePrint(self, head: ListNode) -> List[int]:
#链表末端为空或时返回[]
if not head: return []
#递归回溯时每次返回 当前 list + 当前节点值 [head.val] ,即可实现节点的倒序输出。
return self.reversePrint(head.next) + [head.val]
作者:jyd
来源:力扣(LeetCode)
offer24——反转链表
定义一个函数,输入一个链表的头节点,反转该链表并输出反转后链表的头节点。
解题思路
使用递归法遍历链表,当越过尾节点后终止递归,在回溯时修改各节点的 next 引用指向。
算法流程
recur(cur, pre) 递归函数:
- 终止条件:当 cur 为空,则返回尾节点 pre (即反转链表的头节点);
- 递归后继节点,记录返回值(即反转链表的头节点)为 res ;
- 修改当前节点 cur 引用指向前驱节点 pre ;
- 返回反转链表的头节点 res ;
reverseList(head) 函数:
- 调用并返回 recur(head, null) 。传入 null 是因为反转链表后, head 节点指向 null ;
Python代码如下:
class Solution:
def reverseList(self, head: ListNode) -> ListNode:
def recur(cur, pre):
#终止条件,当 cur 为空,则返回尾节点 pre
if not cur: return pre
#递归后继节点直到最后节点,记录返回值(即反转链表的头节点)为 res
res = recur(cur.next,cur)
#修改当前节点 cur 引用指向前驱节点 pre
cur.next = pre
# 返回反转链表的头节点
return res
# 调用递归并返回
return recur(head,None)
作者:jyd
来源:力扣(LeetCode)
offer35——复杂链表的复制
请实现 copyRandomList 函数,复制一个复杂链表。在复杂链表中,每个节点除了有一个 next 指针指向下一个节点,还有一个 random 指针指向链表中的任意节点或者 null。
解题思路
普通链表的节点定义如下:
# Definition for a Node.
class Node:
def __init__(self, x: int, next: 'Node' = None):
self.val = int(x)
self.next = next
本题链表的节点定义如下:
# Definition for a Node.
class Node:
def __init__(self, x: int, next: 'Node' = None, random: 'Node' = None):
self.val = int(x)
self.next = next
self.random = random
给定链表的头节点 head ,复制普通链表很简单,只需遍历链表,每轮建立新节点 + 构建前驱节点 pre 和当前节点 node 的引用指向即可。
本题链表的节点新增了 random 指针,指向链表中的 任意节点 或者 null。这个 random 指针意味着在复制过程中,除了构建前驱节点和当前节点的引用指向 pre.next ,还要构建前驱节点和其随机节点的引用指向 pre.random 。
本题难点:在复制链表的过程中构建新链表各节点的 random 引用指向。
class Solution:
def copyRandomList(self, head: 'Node') -> 'Node':
cur = head
dum = pre = Node(0)
while cur:
node = Node(cur.val) # 复制节点 cur
pre.next = node # 新链表的 前驱节点 -> 当前节点
# pre.random = '???' # 新链表的 「 前驱节点 -> 当前节点 」 无法确定
cur = cur.next # 遍历下一节点
pre = node # 保存当前新节点
return dum.next
算法流程
利用哈希表的查询特点,考虑构建原链表节点和新链表对应节点 的键值对映射关系,再遍历构建新链表各节点的 next 和 random 引用指向即可。
1.若头节点 head 为空节点,直接返回 null ;
2.初始化: 哈希表 dic , 节点 cur 指向头节点;
3.复制链表:
- 建立新节点,并向 dic 添加键值对 (原 cur 节点, 新 cur 节点) ;
- cur 遍历至原链表下一节点;
4.构建新链表的引用指向:
- 构建新节点的 next 和 random 引用指向;
- cur 遍历至原链表下一节点;
5.返回值: 新链表的头节点 dic[cur] ;
class Solution:
def copyRandomList(self, head: 'Node') -> 'Node':
#若头节点 head 为空节点,直接返回 null
if not head: return
# 初始化哈希表,用于添加原节点cur:新节点cur
dic = {}
# 复制各节点,并建立 “原节点 -> 新节点” 的 Map 映射
# 将 cur 指针重置为 head 头结点进行遍历
cur = head
while cur:
dic[cur] = Node(cur.val)
cur = cur.next
cur = head
# 构建新节点的 next 和 random 指向
while cur:
dic[cur].next = dic.get(cur.next)
dic[cur].random = dic.get(cur.random)
cur = cur.next
# 返回新链表的头节点
return dic[head]
作者:jyd
来源:力扣(LeetCode)