代码随想录27期|Python|Day4|24、两两交换链表中的节点|19、删除链表的倒数第N个节点|面试题02.07.链表相交|142、环形链表II

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

思路

需要3次交换,主要是搞清楚交换的顺序和保存。(图:代码随想录)

方法一:循环+虚拟头节点

·cur指向2(此前需要保存1为temp1)

·2指向1(temp1赋值给2,此前需要保存3为temp2)

·1指向3(temp2赋值给1)

# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution(object):
    def swapPairs(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        # 循环+虚拟头节点版本
        dummy_head = ListNode(0, head)
        cur = dummy_head
        while cur.next and cur.next.next:  # 判断后两位都是可以交换的
            # 先保存原来的顺秀,对应图上的2、3
            temp1 = cur.next
            temp2 = cur.next.next.next
            # 嫁接cur到2
            cur.next = cur.next.next
            # 嫁接2到1
            cur.next.next = temp1
            # 嫁接1到3
            cur.next.next.next = temp2
            # 更新cur跨过2位
            cur = cur.next.next

        return dummy_head.next #返回虚拟节点的下一位(2)

方法二:递归

递归相当于把head向后传递,也就是next作为首节点依次翻转。

注意,最终return的是cur,是第一次交换的cur。

# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution(object):
    def swapPairs(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        # 递归
        if head is None or head.next is None:
            return head
        
        pre = head
        cur = head.next
        next = head.next.next


        cur.next = pre
        pre.next = self.swapPairs(next)

        return cur

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

思路

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

# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution(object):
    def removeNthFromEnd(self, head, n):
        """
        :type head: ListNode
        :type n: int
        :rtype: ListNode
        """
        dummy_head = ListNode(0, head)
        fast = dummy_head
        slow = dummy_head

        # 先让 fast 领先slow n 个位置
        for _ in range(n):
            fast = fast.next

        # 当fast走到末尾,slow指向的就是倒数第n个节点前一个节点
        while fast.next:
            fast = fast.next
            slow = slow.next

        slow.next = slow.next.next

        return dummy_head.next

面试题 02.07.链表相交

思路

注意!这里的相交不是值相等,而是指针相等,所以不能采取一一对应的遍历的方式,而嵌套for带来时间上开销太大。

链表长度+同时出发

假设A比B长,那么只需要将A和B对齐,再依次往后找指针相同的点即可。

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

class Solution(object):
    def getIntersectionNode(self, headA, headB):
        """
        :type head1, head1: ListNode
        :rtype: ListNode
        """
        # 链表长度 + 同时出发
        # Step 1:获取A、B长度
        lenA, lenB = 0, 0
        cur = headA
        while cur:
            cur = cur.next
            lenA += 1
        cur = headB
        while cur:
            cur = cur.next
            lenB += 1
        # Step 2:对齐curA、curB
        curA, curB = headA, headB
        if lenB > lenA:  # 如果B的长度比A长,那么交换两个链表,始终保持A是长的那一个
            curA, curB = curB, curA
            lenA, lenB = lenB, lenA
        for _ in range(lenA - lenB):  # 只移动curA,实现对齐
            curA = curA.next
        # Step 3:寻找交叉点
        while curA:
            if curA == curB:
                return curA
            else:
                curA = curA.next
                curB = curB.next
        return None

链表长度+同时出发(函数复用版)

将以上获取长度和对齐的步骤实现封装复用。

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

class Solution(object):
    def getIntersectionNode(self, headA, headB):
        """
        :type head1, head1: ListNode
        :rtype: ListNode
        """
        # 链表长度 + 同时出发(复用函数型)
        lenA, lenB = self.getlen(headA), self.getlen(headB)
        curA, curB = self.align(headA, headB, lenA, lenB)
        
        while curA and curB:
            if curA == curB:
                return curA
            else:
                curA = curA.next
                curB = curB.next
        return None
        
    def getlen(self, head):
        len = 0
        while head:
            head = head.next
            len += 1
        return len

    def align(self, headA, headB, lenA, lenB):
        if lenB > lenA:
            headA, headB = headB, headA
            lenA, lenB = lenB, lenA
        for _ in range (lenA - lenB):
            headA = headA.next
        return headA, headB

循环自动对齐法(巧妙,值得借鉴)

        while curA != curB:
            curA = curA.next if curA else headB
            curB = curB.next if curB else headA
        return curA

首先我们假设lenA 比 lenB大,实际情况下都可以,这里方便描述:

Step 1:此时A、B都没有被穷尽,所以都执行next操作;

Step 2:此时B被穷尽了,curB跳转到A的开头,此时curA所在的位置超前curB正好是lenB个位置;

Step 3:接着A被穷尽了,curA跳转到B的开头,此时curB所在的位置是距离A的结尾lenB个位置的地方;而curA距离B的结尾也是lenB个位置,相当于实现了对齐。

完整代码如下,

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

class Solution(object):
    def getIntersectionNode(self, headA, headB):
        """
        :type head1, head1: ListNode
        :rtype: ListNode
        """
        # 循环自动对齐法
        if not headA or not headB:  # 边界情况:A或B有一个是空的
            return None
        
        curA, curB = headA, headB

        while curA != curB:
            curA = curA.next if curA else headB
            curB = curB.next if curB else headA
        return curA

142.环形链表II

思路

快慢指针+追及

可以简单描述为:快指针一次走2格,慢指针一次走1格,直到相遇。此时从头和相遇点分别按照一次走1格来遍历,直到相遇,相遇的点就是所求的环的入口。(图:代码随想录)

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

class Solution(object):
    def detectCycle(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        # 快慢指针
        fast, slow = head, head
        while fast and fast.next:
            slow = slow.next  # 慢指针一次走1个
            fast = fast.next.next  # 快指针一次走2个

            if fast == slow:  # 当2个指针相遇
                slow = head  # 从起始位置开始遍历,直到遇见
                while fast != slow:
                    fast = fast.next
                    slow = slow.next
                return slow  # 相遇返回指针
        return None  # 没相遇返回null

集合法(描述简单,但内存大)

只需要判断现在的是不是以前出现过了就可以。为此设置一个集合专门用来盛放已经遇到的节点。

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

class Solution(object):
    def detectCycle(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        # 集合法
        visited = set()  # 创建一个盛放已经遍历过的点的集合
        cur = head
        while cur:
            if cur in visited:  # 见到过直接返回cur
                return cur
            visited.add(cur)  # 没见过的就加进来
            cur = cur.next
        return None

第四天完结🎉

  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值