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

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/wstcjf/article/details/78064842

面试题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变成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 = 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




猜你喜欢

转载自blog.csdn.net/wstcjf/article/details/78064842