链表应用

链表

链表相关的典型应用如下:

序号 题目
1 203. 移除链表元素
2 86. 分隔链表
3 206. 反转链表
4 160. 相交链表
5 92. 反转链表 II

应用

应用1:Leetocde.203

题目

203. 移除链表元素

解题思路

由于头结点也可能被删除,所以我们事先创建一个哑结点。

遍历过程中,如果遇到相等的节点,则跳过下一个节点,将当前节点的指针指向下下个节点

代码

class Solution:
    def removeElements(self, head: ListNode, val: int) -> ListNode:
        # 由于头结点也可能被删除,所以创建一个哑结点
        dummy = ListNode(-1)
        dummy.next = head
        p = dummy
        while p.next:
            # 如果遇到相等的节点,则跳过下一个节点,将当前节点的指针指向下下个节点
            if p.next.val == val:
                p.next = p.next.next
            else:
                p = p.next
        return dummy.next

应用2:Leetocde.86

题目

86. 分隔链表

解题思路

在遍历过程中,将原有的链表分成两部分,使用两个 \(dumy\) 节点 \(large\)\(small\) ,用于分别记录大于 \(x\) 的节点和小于 \(x\) 的节点,遍历完成之后,将大链表,连接到小链表的结尾即可。

代码实现

class Solution:
    def partition(self, head: Optional[ListNode], x: int) -> Optional[ListNode]:
        small = ListNode(0)
        large = ListNode(0)
        large_first = large
        small_first = small
        pointer = head
        while pointer:
            if pointer.val < x:
                small.next = pointer
                small = small.next
            else:
                large.next = pointer
                large = large.next
            pointer = pointer.next
        large.next = None
        small.next = large_first.next
        return small_first.next

应用3:Leetocde.206

题目

206. 反转链表

解题思路

双向链表只需要一个节点就可以找到它的前后两个节点,单向链表需要两个节点,才能知道当前节点的前后节点。

单向链表逆序的时候,需要按照如下步骤操作:

  • 先用一个临时指针temp,指向当前节点的下一个节点;
  • 将当前节点的next指针,指向前一个节点;
  • 前一个指针,移动一步;
  • 后一个指针,移动一步;

如图所示:

链表倒序.svg

代码实现


class ListNode:
    def __init__(self, val=0, next=None):
        self.val = val
        self.next = next

class Solution:
    def reverseList(self, head: ListNode) -> ListNode:
        p1 = None
        p2 = head
        while p2:
            temp = p2.next
            p2.next = p1
            p1 = p2
            p2 = temp
        return p1

应用4:Leetocde.160

题目

160. 相交链表

解题思路

用两个指针分别指向两个链表,当指针移动到链表结尾后,再交换两个指针的指向,如果两个链表存在交点,则两个指针会同时相等。

代码

class Solution:
    def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
        if not headA or not headB:
            return None

        p1 = headA
        p2 = headB
        while p1 != p2:
            p1 = headB if not p1 else p1.next
            p2 = headA if not p2 else p2.next
        return p1

应用5:Leetocde.92

题目

92. 反转链表 II

解题思路

遍历一次链表,将中间的子链表倒序,遍历时,记录前驱和后驱节点,倒序完成后,将前驱和后驱节点连接即可。

下面,我们以如下用例,来介绍算法流程:

head = [1,2,3,4,5,6], left = 2, right = 5

image

步骤如下:

  1. 初始化两个指针 \(P0\)\(P\),用于记录当前一个节点和当前节点:

image

  1. 向后移动 \(left\) 步:

image

  1. 初始化两个指针 \(P1\)\(P2\),用于单链表 \([2,3,4,5]\) 倒序:

image

  1. 使用一个临时指针 \(Temp\) 记录下一个节点:

image

  1. 使用一个 \(P2\) 指向节点的 \(next\) 指针指向 \(P1\)

image

  1. 同时\(P1\)\(P2\) 分别后移一步:

image

  1. 重复步骤 \(5\)\(6\),将单链表 \([2,3,4,5]\) 完成倒序:

image

  1. 将指针 \(P\) 指向的节点的 next 指针指向 \(P2\) 指向的节点:

image

  1. 将指针 \(P0\) 指向的节点的 next 指针指向 \(P1\) 指向的节点:

image

代码

class Solution:
    def reverseBetween(self, head: ListNode, left: int, right: int) -> ListNode:
        post = head
        before = None

        # 用指针p移动到left所在的节点
        for _ in range(1, left):
            before = post
            post = post.next

        # 将中间的子链表倒序
        p1 = None
        p2 = post
        for _ in range(left, right + 1):
            temp = p2.next
            p2.next = p1
            p1 = p2
            p2 = temp

        # 记录后驱节点
        if post:
            post.next = p2

        # 将前驱链表指向倒序后的链表表头
        if before:
            before.next = p1
        # 如果前驱节点是head则直接指向p1
        else:
            head = p1
        return head
posted @ 2023-02-28 23:02  LARRY1024  阅读(20)  评论(0编辑  收藏  举报