链表LinkedList
概念理解
理解链表概念
python数据结构之链表(一)
python数据结构之链表(linked list)
单链表结构python应用1
单链表结构python应用2
题目
003-从尾到头打印列表
输入一个链表,按链表从尾到头的顺序返回一个ArrayList。
(注意判断空集)
方法一:递归算法,第一次直接传递到最后一个next返回,再找到倒数第二级的next再返回,
# -*- coding:utf-8 -*-
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
# 返回从尾部到头部的列表值序列,例如[1,2,3]
def printListFromTailToHead(self, listNode):
# write code here
if listNode is None:
return []
else:
return self.printListFromTailToHead(listNode.next) + [listNode.val]
方法二:将单链表储存为数组,然后按照数组的索引逆序进行反转。
class Solution:
# 返回从尾部到头部的列表值序列,例如[1,2,3]
def printListFromTailToHead(self, listNode):
# write code here
stack, h = [], listNode
while h:
stack.append(h.val)
h = h.next
return stack[::-1]
014-链表中倒数第k个节点
输入一个链表,输出该链表中倒数第k个结点。
注意输出是节点,不是节点值。
方法一:两个指针,快指针先走k-1步,然后两个一起走,快指针走到尾节点时,慢指针在倒数第k个节点。
需考虑head没有值,k<=0时和k>head长度的情况。
class Solution:
def FindKthToTail(self, head, k):
# write code here
if head == None or k<=0:
return None
p1 = p2 = head
for _ in range(k):
if p2:
p2 = p2.next
else:
return None
while p2:
p1, p2 = p1.next, p2.next
return p1
方法二:引入数组。
注意:while head.next
如果是一个空链表,会报错;
res.append(head.val)
返回的是节点的值,题目要求返回节点,输出的是一个节点地址,可以根据这个地址遍历剩余节点。
if head == None or k<1:
return None
res = []
while head:
res.append(head)
head = head.next
if k>len(res):
return None
return res[-k]
015-反转链表
输入一个链表,反转链表后,输出新链表的表头
class Solution:
# 返回ListNode
def ReverseList(self, pHead):
# write code here
prev = None
if not pHead or not pHead.next:
return pHead
while pHead:
tmp = pHead.next
pHead.next = prev
prev = pHead
pHead = tmp
return prev
注意python连续赋值的用法
class Solution:
# 返回ListNode
def ReverseList(self, pHead):
# write code here
prev = None
if not pHead or not pHead.next:
return pHead
while pHead:
pHead.next, prev, pHead = prev, pHead, pHead.next
return prev
016-合并两个或k个有序链表
输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。
方法一迭代:
- 比较两个链表的首结点,哪个小的的结点则合并到第三个链表尾结点,并向前移动一个结点。
- 步骤一结果会有一个链表先遍历结束,或者没有
- 第三个链表尾结点指向剩余未遍历结束的链表
- 返回第三个链表首结点
class Solution:
# 返回合并后列表
def Merge(self, pHead1, pHead2):
# write code here
tmp = ListNode(0)
pHead = tmp
while pHead1 and pHead2:
if pHead1.val <= pHead2.val:
tmp.next = pHead1
pHead1 = pHead1.next
else:
tmp.next = pHead2
pHead2 = pHead2.next
tmp = tmp.next
if pHead1:
tmp.next = pHead1
elif pHead2:
tmp.next = pHead2
return pHead.next
def mergeTwoLists(l1, l2):
l = head = ListNode(0)
while l1 and l2:
if l1.val <= l2.val:
l.next, l1 = l1, l1.next
else:
l.next, l2 = l2, l2.next
l = l.next
l.next = l1 or l2
return head.next
方法二递归:
可更换return位置查看原理
def Merge(self, pHead1, pHead2):
# write code here
if not pHead1 or not pHead2:
return pHead1 or pHead2
if pHead1.val < pHead2.val:
pHead1.next = self.Merge(pHead1.next, pHead2)
return pHead1
else:
pHead2.next = self.Merge(pHead1, pHead2.next)
return pHead2
方法三数组sort():
def Merge(self, pHead1, pHead2):
# write code here
res = []
while pHead1:
res.append(pHead1.val)
pHead1 = pHead1.next
while pHead2:
res.append(pHead2.val)
pHead2 = pHead2.next
res.sort()
dummy = ListNode(0)
pre = dummy
for i in res:
node = ListNode(i)
pre.next = node
pre = pre.next
return dummy.next
025-复杂链表的复制
输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针random指向一个随机节点),请对此链表进行深拷贝,并返回拷贝后的头结点。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)
*解题思路:
*1、遍历链表,复制每个结点,如复制结点A得到A1,将结点A1插到结点A后面;
*2、重新遍历链表,复制老结点的随机指针给新结点,如A1.random = A.random.next;
*3、拆分链表,将链表拆分为原链表和复制后的链表
# class RandomListNode:
# def __init__(self, x):
# self.label = x
# self.next = None
# self.random = None
class Solution:
# 返回 RandomListNode
def Clone(self, pHead):
if not pHead:
return None
# step1 加入A'
dummy = pHead # 让dummy指向表头
while dummy:
copynode = RandomListNode(dummy.label) # 创建节点意味着开辟新的内存空间
copynode.next = dummy.next
dummy.next = copynode
dummy = copynode.next
# step2 A'添加random
dummy = pHead # 让dummy指向表头
while dummy:
copynode = dummy.next
if dummy.random:
copynode.random = dummy.random.next
dummy = copynode.next
# step3 拆分A和A'
dummy = pHead
copyHead = pHead.next # pHead为A与A‘混合的指针
while dummy:
copynode = dummy.next
dummy.next = copynode.next
if dummy.next == None:
copynode = None
else:
copynode.next = dummy.next.next
dummy = dummy.next
return copyHead
036-两个链表的第一个公共结点
输入两个链表,找出它们的第一个公共结点。(注意因为传入数据是链表,所以错误测试数据的提示是用其他方式显示的,保证传入数据是正确的)
假定 List1长度: a+n List2 长度:b+n, 且 a<b
- p1 会先到链表尾部, 这时p2 走到 a+n位置,将p1换成List2头部
- p2 再走b+n-(n+a) =b-a 步到链表尾部,这时p1也走到List2的b-a位置,还差a步就到可能的第一个公共节点。
- 将p2 换成 List1头部,p2走a步也到可能的第一个公共节点。
- 如果恰好p1==p2,那么p1就是第一个公共节点。 或者p1和p2一起走n步到达列表尾部,二者没有公共节点,退出循环。 同理a>=b.
时间复杂度O(n+a+b)
不同情况考虑
a.长度相同的:1. 有公共结点的,第一次就遍历到;2. 没有公共结点的,走到尾部NULL相遇,返回NULL;
b.长度不同的:1. 有公共结点的,第一遍差值就出来了,第二遍就会一起到公共结点;2. 没有公共结点的,第二次遍历一起到结尾NULL。
class Solution:
def FindFirstCommonNode(self, pHead1, pHead2):
# write code here
p1 = pHead1
p2 = pHead2
while p1!=p2:
p1 = p1.next if p1 else pHead2
p2 = p2.next if p2 else pHead1
return p1
055-链表中环的入口结点
给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null。
思路:
设置快慢指针,都从链表头出发,快指针每次走两步,慢指针一次走一步,假如有环,一定相遇于环中某点(结论1)。接着让两个指针分别从相遇点和链表头出发,两者都改为每次走一步,最终相遇于环入口(结论2)。
解析
时间复杂度是O(n),空间复杂度为O(1)
class Solution:
def EntryNodeOfLoop(self, pHead):
# write code here
fast = slow = pHead
while fast and fast.next:
fast, slow = fast.next.next, slow.next
if fast is slow: break
else: return None
while pHead is not slow:
pHead, slow = pHead.next, slow.next
return pHead
056-删除链表中重复的结点
在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。 例如,链表1->2->3->3->4->4->5 处理后为 1->2->5
方法一:非递归
- 首先添加一个头节点,以方便碰到第一个,第二个节点就相同的情况
- 设置 p1 ,p2 指针, p2指针指向当前确定不重复的那个节点,而p1指针相当于工作指针,一直往后面搜索。
class Solution:
def deleteDuplication(self, pHead):
# write code here
Head = ListNode(0)
Head.next = pHead
p2, p1 = Head, Head.next
while p1:
# p1.next=None的话,None.val会报错
if p1.next and p1.next.val == p1.val:
while p1.next and p1.next.val == p1.val:
p1 = p1.next
p2.next = p1.next
p1 = p2.next
else:
p1, p2 = p1.next, p2.next
return Head.next
方法二:递归
每次递归:删除目前指针向后的第一段连续节点。保证下一次递归的头结点与之后的不重复
class Solution:
def deleteDuplication(self, pHead):
# write code here
if not pHead: return None
if pHead and pHead.next==None: return pHead
curr = pHead
if pHead.next.val == pHead.val:
while curr and curr.val == pHead.val:
curr = curr.next
return self.deleteDuplication(curr)
else:
curr = pHead.next
pHead.next = self.deleteDuplication(curr) #重点
return pHead