面试题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:合并两个排序的链表
输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。
思路:
# -*- 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