剑指offer题解 python_剑指offer 链表题最佳解汇总 Python

面试题5: 从尾到头打印链表

输入一个链表,从尾到头打印链表每个节点的值。

思路:

class Solution:

# 返回从尾部到头部的列表值序列,例如[1,2,3]

def printListFromTailToHead(self, listNode):

l = []

# 直接遍历一遍链表保存结果到list中,再返回倒序的list即可

while listNode:

l.append(listNode.val)

listNode = listNode.next

return l[::-1]

面试题15:链表中倒数第k个结点

输入一个链表,输出该链表中倒数第k个结点。

思路:个人总结最佳算法,先计算链表的长度,然后计算找到倒数第k个需要几次循环,并判断其中关系。最后用for循环,不断将指针指向下一个节点,即为所求。

# -*- coding:utf-8 -*-

# class ListNode:

# def __init__(self, x):

# self.val = x

# self.next = None

class Solution:

def FindKthToTail(self, head, k):

len_node = 0

temp = head

while temp:

temp = temp.next

len_node += 1

run_times = len_node - k

if run_times < 0 or k < 0:

return

for i in range(run_times):

head = head.next

return head

面试题16:反转链表

输入一个链表,反转链表后,输出链表的所有元素。

思路:定义两个变量,分别保存前指针和后指针。

# -*- coding:utf-8 -*-

# class ListNode:

# def __init__(self, x):

# self.val = x

# self.next = None

class Solution:

# 返回ListNode

def ReverseList(self, pHead):

if not pHead:

return None

# 当前节点是pHead,Pre为当前节点的前一节点,Next为当前节点的下一节点

# 需要pre和next的目的是让当前节点从pre->head->next1->next2变成prenext2

# 即pre让节点可以反转所指方向,但反转之后如果不用next节点保存next1节点的话,此单链表就此断开了

# 所以需要用到pre和next两个节点

# 1->2->3->4->5

# 15

Pre = None

Next = None

while pHead:

Next = pHead.next # 保存当前结点的next指针,方便反转第一次后,在链表断开的情况下,依然找到原来的下一个结点

pHead.next = Pre # 反转链表,将当前结点的next指针指向前一个结点

Pre = pHead # 保存当前结点,更新Pre,方便下一次调用

pHead = Next # 让pHead按原来顺序走到第二个结点

return Pre

面试题17:合并两个排序的链表

输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。

思路:

1282225194655563776.htm

# -*- coding:utf-8 -*-

# class ListNode:

# def __init__(self, x):

# self.val = x

# self.next = None

class Solution:

# 返回合并后列表

def Merge(self, pHead1, pHead2):

merged = None

# 当pHead1为空时,返回pHead2

if not pHead1:

return pHead2

# 当pHead2为空时,返回pHead1

if not pHead2:

return pHead1

# 第一个链表中的第一个点小于第二个链表第一个点,那么merged第一个点就是pHead1的第一个点

# 对于他的next,继续执行递归

if pHead1.val < pHead2.val:

merged = pHead1

merged.next = self.Merge(pHead1.next, pHead2)

# 第一个链表中的第一个点大于第二个链表第一个点,那么merged第一个点就是pHead1的第一个点

# 对于他的next,继续执行递归

else:

merged = pHead2

merged.next = self.Merge(pHead1, pHead2.next)

return merged

面试题26:复杂链表的复制

输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点),返回结果为复制后复杂链表的head。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)

思路:

# -*- coding:utf-8 -*-

# 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 pHead

# 开辟一个新结点

copy = RandomListNode(pHead.label)

copy.next = pHead.next

copy.random = pHead.random

# 递归剩余结点

copy.next = self.Clone(pHead.next)

return copy

面试题37:两个链表的第一个公共结点

输入两个链表,找出它们的第一个公共结点。

思路:

# -*- coding:utf-8 -*-

# class ListNode:

# def __init__(self, x):

# self.val = x

# self.next = None

class Solution:

def FindFirstCommonNode(self, pHead1, pHead2):

# 最优解:O(m+n),比放到stack里面做,节省了空间

if not pHead1 or not pHead2:

return None

length1 = 0

length2 = 0

p1 = pHead1

p2 = pHead2

# 分别计算两个链表的长度

while p1:

length1 += 1

p1 = p1.next

while p2:

length2 += 1

p2 = p2.next

# 根据两个链表的长度,确定长、短链表和它们之间的长度之差

if length1 >= length2:

step = length1 - length2

longList = pHead1

shortList = pHead2

else:

step = length2 - length1

longList = pHead2

shortList = pHead1

# 让长链表先走step步

for i in range(0,step):

longList = longList.next

# 同时遍历两个链表,让他们不断指向next,并判断何时相等,相等时返回任一一个链表即可

while longList and shortList:

if longList == shortList:

return longList

longList = longList.next

shortList = shortList.next

return None

面试题56:链表中环的入口结点

一个链表中包含环,请找出该链表的环的入口结点。

思路:

第一步,找环中相汇点。分别用p1,p2指向链表头部,p1每次走一步,p2每次走二步,直到p1==p2找到在环中的相汇点。

第二步,找环的入口。接上步,当p1==p2时,p2所经过节点数为2x,p1所经过节点数为x,设环中有n个节点,p2比p1多走一圈有2x=n+x; n=x;可以看出p1实际走了一个环的步数,再让p2指向链表头部,p1位置不变,p1,p2每次走一步直到p1==p2;此时p1指向环的入口。

# -*- coding:utf-8 -*-

# class ListNode:

# def __init__(self, x):

# self.val = x

# self.next = None

class Solution:

def EntryNodeOfLoop(self, pHead):

if pHead ==None:

return 1

if pHead.next==None or pHead.next.next==None:

return None

# 使用快慢指针,p每次走两步,q每次走一步

p = pHead.next.next

q = pHead.next

# 第一次循环,直到p和q相遇,p每次走两步,q每次走一步

while p!=q:

p = p.next.next

q = q.next

if p.next == None or p.next.next ==None:

return None

# 第二次循环,直到p和q相遇,让快指针p回到开始的点,p和q每次都走一步

p = pHead

while p!=q:

p = p.next

q = q.next

return q

面试题57:删除链表中重复的结点

在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。 例如,链表1->2->3->3->4->4->5 处理后为 1->2->5

思路:

方法一:

# -*- coding:utf-8 -*-

# class ListNode:

# def __init__(self, x):

# self.val = x

# self.next = None

class Solution:

def deleteDuplication(self, pHead):

temp = []

# 先将pHead中所有结点的value全部放到temp列表中去

while head:

temp.append(head.val)

head = head.next

result = ListNode(0) # 创建一个新的指针

head = result # 让head指向这个指针

for i in temp:

if temp.count(i) == 1:# 对于temp中的元素,如果出现次数等于1就添加到head的next指针

head.next = ListNode(i)

head = head.next

return result.next

# 最后返回result.next,这里用head是因为如果直接操作result最后result会指向最后一个指针无法返回需要的结果

方法二:

# -*- coding:utf-8 -*-

# class ListNode:

#     def __init__(self, x):

#         self.val = x

#         self.next = None

class Solution:

def deleteDuplication(self, pHead):

if not pHead:

return None

first = ListNode(0) # 生成一个头指针

last = first

while pHead and pHead.next:

if pHead.val == pHead.next.val:

while pHead.next and pHead.val == pHead.next.val:

pHead = pHead.next

else:

last.next = pHead # 删除链表中重复的结点

last = last.next

pHead = pHead.next

last.next = pHead

return first.next

扩展:判断链表是否有环

思路:

# -*- coding:utf-8 -*-

# class ListNode:

# def __init__(self, x):

# self.val = x

# self.next = None

class Solution:

def hasCycle(self, pHead):

if pHead ==None:

return False

if pHead.next==None or pHead.next.next==None:

return False

# 使用快慢指针,p每次走两步,q每次走一步

slow = pHead.next.next

quick = pHead.next

while slow.next and quick.next:

if slow == quick:

return True

slow = slow.next.next

quick = quick.next

return False

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值