链表Part02

本文介绍了如何通过链表操作解决一系列问题,包括两两交换链表中的节点、删除链表的倒数第N个节点、使用快慢双指针判断链表是否存在环以及找到链表相交的起始节点。
摘要由CSDN通过智能技术生成

目录

两两交换链表中的结点

删除链表的倒数第N个节点

快慢双指针 

链表相交

环形链表II

 快慢指针法-判断环


两两交换链表中的结点

给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。

 本题首先要找规律:不难看出其实就是两个元素为一组,进行交换,再指向下一组

不难看出,交换后,只需要cur = cur.next就可以对3、4重复步骤1、2、3。

❗注意我们返回的应该是交换后链表的头节点

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def swapPairs(self, head: Optional[ListNode]) -> Optional[ListNode]:
        if head == None or head.next == None:
            return head
        cur = ListNode(None,head)
        p = head.next
        while cur.next and cur.next.next:
            temp1 = cur.next
            cur.next = cur.next.next
            temp2 = cur.next.next
            cur.next.next = temp1
            temp1.next = temp2
            cur = temp1
        return p

另外,这题也可以用递归

# 递归版本
# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next

class Solution:
    def swapPairs(self, head: Optional[ListNode]) -> Optional[ListNode]:
        if head is None or head.next is None:
            return head

        # 待翻转的两个node分别是pre和cur
        pre = head
        cur = head.next
        next = head.next.next
        
        cur.next = pre  # 交换
        pre.next = self.swapPairs(next) # 将以next为head的后续链表两两交换
         
        return cur

删除链表的倒数第N个节点

给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。 

本题比较简单,只需要先设一个虚拟头结点,然后进行dummy_head.next的循环length-n次。

快慢双指针 

但是,如果要实现一趟扫描,就复杂一点。这里要引入快慢双指针:

双指针的经典应用,如果要删除倒数第n个节点,让fast移动n步,然后让fast和slow同时移动,直到fast指向链表末尾。删掉slow所指向的节点就可以了。

  •  设置虚拟头节点可以方便处理删除头节点的问题
  • fast移动n+1步→这样后面fast和slow同时移动时,两者始终间隔n→slow最终指向删除结点的前一个位置
  • 注意区分链表末尾与链表最后一个元素:链表末尾为None;而链表最后一个(倒数第一个)元素是4

(下图n=2)

 ❗不能return head,因为在使用虚拟头节点删除头节点的方法中,我们是通过断开了dummy_head与head之间的链,而不是使head = head.next;如果return head会返回原链表。

 

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def removeNthFromEnd(self, head: Optional[ListNode], n: int) -> Optional[ListNode]:
        dummy_head = ListNode(None,head)
        fast,slow = dummy_head,dummy_head

        for _ in range(n+1):    #fast先走n+1步
            fast = fast.next

        while fast:
            fast = fast.next    #fast和slow同时走,直到fast到链尾
            slow = slow.next
        
        slow.next = slow.next.next  #删除结点

        return dummy_head.next

链表相交

给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null 。

图示两个链表在节点 c1 开始相交

题目数据 保证 整个链式结构中不存在环。

注意,函数返回结果后,链表必须 保持其原始结构 。

 由图可以看出,如果A、B两个链表分开,其实应该是末端对齐,然后进行匹配的(因为他们一定从某一节点起到末尾是相同的)

 ❗遍历长度时用cur(=head)来遍历→如果用head来遍历,遍历结束后head指向链尾,链头指针被改变,无法再次遍历

class Solution:
    def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
        lenA, lenB = 0, 0
        cur = headA
        while cur:         # 求链表A的长度
            cur = cur.next 
            lenA += 1
        cur = headB 
        while cur:         # 求链表B的长度
            cur = cur.next 
            lenB += 1
        curA, curB = headA, headB
        if lenA > lenB:     # 让curB为最长链表的头,lenB为其长度
            curA, curB = curB, curA
            lenA, lenB = lenB, lenA 
        for _ in range(lenB - lenA):  # 让curA和curB在同一起点上(末尾位置对齐)
            curB = curB.next 
        while curA:         #  遍历curA 和 curB,遇到相同则直接返回
            if curA == curB:
                return curA
            else:
                curA = curA.next 
                curB = curB.next
        return None 

环形链表II

给定一个链表的头节点  head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。

不允许修改 链表。

示例 1:

输入:head = [3,2,0,-4], pos = 1
输出:返回索引为 1 的链表节点
解释:链表中有一个环,其尾部连接到第二个节点。

 快慢指针法-判断环

可以使用快慢指针法,分别定义 fast 和 slow 指针,从头结点出发,fast指针每次移动两个节点,slow指针每次移动一个节点,如果 fast 和 slow指针在途中相遇 ,说明这个链表有环。

在环中,对于slow来说,fast其实在一个一个结点追上他,所以他们必定会在环内相遇。                且相遇点一定在环的入口 (为什么相遇点一定在入口?

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None


class Solution:
    def detectCycle(self, head: ListNode) -> ListNode:
        slow = head
        fast = head
        
        while fast and fast.next:
            slow = slow.next
            fast = fast.next.next
            
            # If there is a cycle, the slow and fast pointers will eventually meet
            if slow == fast:
                # Move one of the pointers back to the start of the list
                slow = head
                while slow != fast:
                    slow = slow.next
                    fast = fast.next
                return slow
        # If there is no cycle, return None
        return None
  • 20
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值