算法训练营 day4 | 链表 part2

24. 两两交换链表中的节点

题目链接

# 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]:
        dummy_head = ListNode(next,head)
        cur = dummy_head
        while (cur.next != None and cur.next.next != None):
            temp1 = cur.next # 存储节点防止断链
            temp2 = cur.next.next.next
            
            cur.next = cur.next.next # 开始交换节点
            cur.next.next = temp1
            temp1.next = temp2
            cur = cur.next.next
        return dummy_head.next

总结:本题依然要用到虚拟头节点。使用temp1和temp2把第一次交换的第二个节点和第二次交换的第二个节点保存下来。防止断链。需要注意的是,循环的判断条件。每次处理cur后面的两个节点。当节点总数量为偶数时,cur指针会被更新到最后一个节点,此时如果下个节点为空,则停止循环,奇数时cur指向倒数第二个节点。还要注意的是必须先判断cur.next然后再判断cur.next.next,反过来的话发生指针异常。

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

题目链接

# 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(next, head)
        quick = dummy_head
        slow = dummy_head
        for _ in range(n+1): 
            quick = quick.next

        while quick != None:
            quick = quick.next
            slow = slow.next
        slow.next = slow.next.next

        return dummy_head.next
            

总结:本题重点要想到使用双指针找到倒数第N个节点,即快指针先走N步,然后快慢指针再同步移动,当快指针为空时,慢指针指向倒数第N个节点。因为需要进行删除链表节点,所以需要拿到被操作节点的前一个节点,所以我们让快指针走N+1步,那么当循环结束时,慢指针指向的就是被操作节点的前一个节点。

160. 链表相交 

题目链接

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

class Solution:
    def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
        lenA, lenB = 0, 0
        cur = headA
        while cur:
            cur = cur.next
            lenA += 1
        cur = headB
        while cur:
            cur = cur.next
            lenB += 1
        curA, curB = headA, headB
        if lenA > lenB: # 让curB始终为最长链表的头
            curA, curB = curB, curA
            lenA, lenB = lenB, lenA
        for _ in range(lenB - lenA):
            curB = curB.next
        while curA:
            if curA == curB:
                return curA
            else:
                curA = curA.next
                curB = curB.next
        return None

 总结:本题主要是让两条链靠墙站着,链表尾部对齐。思想和上一题的快慢指针有点类似。先求出两个链表的长度,让长的链接先走两个链表长度的差值。这时判断指针是否相等,相等的话就可以返回了,不相等再进行后移需要注意:交点不是数值相等,而是指针相等。

142.环形链表II

题目链接

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

class Solution:
    def detectCycle(self, head: Optional[ListNode]) -> Optional[ListNode]:
        slow = head
        fast = head

        while fast and fast.next:
            slow = slow.next
            fast = fast.next.next

            if slow == fast: 
                slow = head 
                while slow != fast:
                    slow = slow.next
                    fast = fast.next
                return slow
        return None

总结:这题有两个重点。

怎么判断有环:利用快慢指针,快指针一次走两步,慢指针一次走一步。如果有环的话,那么快慢指针一定会相遇。

怎么找环的入口处:假设从头结点到环形入口节点 的节点数为x。 环形入口节点到 fast指针与slow指针相遇节点 节点数为y。 从相遇节点 再到环形入口节点节点数为 z。那么有(x + y) * 2 = x + y + n (y + z)。整理得x = (n - 1) (y + z) + z。n一定是大于等于1的,因为 fast指针至少要多走一圈才能相遇slow指针。n=1那么公式就为x=z。从头结点出发一个指针,从相遇节点也出发一个指针,这两个指针每次只走一个节点,那么当这两个指针相遇的时候就是环形入口的节点。n大于1时情况相同,不过是快指针在环里多转了几圈

  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值