【剑指offer】数据结构类--链表LinkedList--8题「fini」

本文深入探讨了链表数据结构的多个核心算法,包括从尾到头打印链表、寻找链表中倒数第k个节点、链表反转、合并有序链表、复杂链表复制、查找公共节点、环入口节点定位及删除重复节点等。提供了详细的实现思路与代码示例,适合初学者和进阶者巩固链表操作技能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

概念理解

理解链表概念
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个有序链表

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

  1. 比较两个链表的首结点,哪个小的的结点则合并到第三个链表尾结点,并向前移动一个结点。
  2. 步骤一结果会有一个链表先遍历结束,或者没有
  3. 第三个链表尾结点指向剩余未遍历结束的链表
  4. 返回第三个链表首结点
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

  1. p1 会先到链表尾部, 这时p2 走到 a+n位置,将p1换成List2头部
  2. p2 再走b+n-(n+a) =b-a 步到链表尾部,这时p1也走到List2的b-a位置,还差a步就到可能的第一个公共节点。
  3. 将p2 换成 List1头部,p2走a步也到可能的第一个公共节点。
  4. 如果恰好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
方法一:非递归

  1. 首先添加一个头节点,以方便碰到第一个,第二个节点就相同的情况
  2. 设置 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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值