(二刷)代码随想录算法训练营day4 | 24. 两两交换链表中的节点, 19.删除链表的倒数第N个节点, 160. 链表相交 , 142.环形链表II

题目:链表

24. 两两交换链表中的节点 (medium)

  • 终止条件的判断

  1. 由于是两两交换,那么就自然需要考虑偶数和奇数个节点的情况:偶数时curr.next = None终止;奇数时curr.next.next = None终止。
  2. 以上讨论同样适用于空链表的情况,因为链表节点数量是0,就符合偶数的情况。
  • 那么为什么不可以先写curr.next.next != None呢?

  1. 如果这样写:while (curr.next.next and currr.next),那么当curr.next为None的时候,这样curr.next.next就是对空指针取值,则会出现空指针异常
  2. 由于curr是定义的dummy_head,那么就不会为空了,因此就不需要对curr进行判断。

  •  不难想到需要用temp来保存某一节点,那么为什么有如下这个问题呢?

(二刷)代码随想录算法训练营day4 | 24. 两两交换链表中的节点, 19.删除链表的倒数第N个节点, 160. 链表相交 , 142.环形链表II_第1张图片

  • 题解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(next=head)
        curr = dummy_head
        
        while curr.next and curr.next.next:
            temp = curr.next
            temp1 = curr.next.next.next
            
            curr.next = curr.next.next
            curr.next.next = temp
            temp.next = temp1
            
            curr = curr.next.next
            
        return dummy_head.next
        
  • 题解2:更好

(二刷)代码随想录算法训练营day4 | 24. 两两交换链表中的节点, 19.删除链表的倒数第N个节点, 160. 链表相交 , 142.环形链表II_第2张图片

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 = ListNode(0, next = head)
        prev = dummy
        curr = head

        while curr and curr.next:
            temp1 = curr.next
            temp2 = curr.next.next
            
            prev.next = temp1
            temp1.next = curr
            curr.next = temp2

            prev = curr
            curr = temp2
        
        return dummy.next

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

  • 思路:

    • 如果要删除倒数第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
        """
        
        
        slow = head
        fast = head
        
        while n > 0:
                fast=fast.next
                n-=1
               
        # commenting out the following two lines will be wrong, since had to deal with case when only one node is in the linked list.    
        # Thus, for consistent, better using dummy_head
        if fast == None and n == 0:
            return head.next
        
        while fast.next:
            slow = slow.next
            fast = fast.next

        slow.next = slow.next.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(0, next = head)
        slow = fast = dummy_head
        
        while n >= 0:
            fast = fast.next
            n -= 1
        
        while fast:
            slow = slow.next
            fast = fast.next
        
        slow.next = slow.next.next
        
        return dummy_head.next

160. 链表相交

  • 求两个链表交点节点的指针。 交点不是数值相等,而是指针相等。

  • 题解1: O(n+m), O(n)

    • 如果temp.add(currA.val),那么就是上面所说的问题了,要的是指针不是数值!

# 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) -> Optional[ListNode]:
        
        #solution 1: 
        # time complexity: O(n+m)
        # space complexity: O(n)
        
        temp = set()
        currA = headA
        currB = headB
        
        while currA:
            temp.add(currA)
            currA = currA.next
            
        while currB:
            if currB in temp:
                return currB
            
            currB = currB.next
            
        return None
        
  • 题解2:O(n+m), O(1)

    • trick: 需要将较长链表的头指针指向跟较短链表有相同长度的位置,然后开始一起走并且check是否相同。
    • 因此,要想移动长链表头指针到指定位置,则需要知道两个链表长度差,那么进而需要知道两个链表的长度。
# 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
        """
        
        curA, curB = headA, headB
        
        #to calculate the length
        lenA =0
        lenB = 0
        while curA:
            lenA += 1
            curA = curA.next
        while curB:
            lenB += 1
            curB = curB.next
            
        #calculate the difference of both lengths
        if lenA > lenB:
            diff = lenA - lenB
            curL = headA
            curS = headB
        else:
            diff = lenB - lenA
            curL = headB
            curS = headA
            
        #move the pointer of the longer linked list to the position where has the same subsequent length
        while diff > 0 :
            curL = curL.next
            diff -= 1
            
        # check
        while curL:
            if curL == curS:
                return curL
            curL = curL.next
            curS = curS.next
        
        return None

141. 环形链表

  • 题解1

class Solution:
    def hasCycle(self, head: Optional[ListNode]) -> bool:
        temp = set()
        cur = head

        while cur:
            if cur in temp:
                return True
            temp.add(cur)
            cur = cur.next
        return False
  • 题解2:

fast = slow = head

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

            if slow == fast:
                return True
        
        return False

142.环形链表II

  • trick:找到曾经走过的点

  • 题解1:利用set来保存走过的点,如果在此路过,则返回此点。

Q:难道链表不可以有形同的值吗?这样用set()也无法说明是环的起点?

A:注意加入set()的是指针,因此可以用set()来找起点。

# 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
        """
        
        # space complexity: O(n)
        temp = set()
        curr = head
        
        while curr:
            if curr in temp:
                return curr
            temp.add(curr)
            curr = curr.next
            
        return None
        
  • 题解2:Space complexity: O(1)

# 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]:
        
        fast = slow = head
        while fast and fast.next:
            slow = slow.next
            fast = fast.next.next
            
            if slow == fast: #fast and slow meet
                #define another two pointers for finding the entrance
                index1 = fast #or slow
                index2 = head
                while index1 != index2:
                    index1 = index1.next
                    index2 = index2.next
                    
                return index1 #or index2     
        
        return None

总结:

  1. 对链表的知识点进行了复习,其中一些点是通过大家的讨论才知道的,比如之前没有把指针和节点的区别弄清楚,导致每次由于返回造成错误。这样也仅仅是改一下返回就觉得自己理解了(因为想着只是改了一行代码而已),实际上关键点没有突破。

                

你可能感兴趣的:(链表,算法,数据结构)