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

来源:互联网 发布:淘宝怎么更改支付宝 编辑:程序博客网 时间:2024/05/21 03:20

面试题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 = Noneclass 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 = Noneclass Solution:    # 返回ListNode    def ReverseList(self, pHead):        if not pHead:            return None        # 当前节点是pHead,Pre为当前节点的前一节点,Next为当前节点的下一节点        # 需要pre和next的目的是让当前节点从pre->head->next1->next2变成pre<-head next1->next2        # 即pre让节点可以反转所指方向,但反转之后如果不用next节点保存next1节点的话,此单链表就此断开了        # 所以需要用到pre和next两个节点        # 1->2->3->4->5        # 1<-2<-3 4->5        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 = Noneclass 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 = Noneclass 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 = Noneclass 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 = Noneclass 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 = Noneclass 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 = Noneclass 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 = Noneclass 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