美文网首页
链表 LC.19/83/92/61/143/21/160/141

链表 LC.19/83/92/61/143/21/160/141

作者: M_cory | 来源:发表于2019-05-26 14:58 被阅读0次

    LC.19 Remove Nth Node Form End of List

    Description

    Given a linked list, remove the n-th node from the end of list and return its head.

    Example:

    Given linked list: 1->2->3->4->5, and n = 2.
    
    After removing the second node from the end, the linked list becomes 1->2->3->5.
    

    Note:

    Given n will always be valid.

    Follow up:

    Could you do this in one pass?

    Solution

    • one-pass (trivial) 实际上有两个指针,所以是2-pass
    # Definition for singly-linked list.
    # class ListNode:
    #     def __init__(self, x):
    #         self.val = x
    #         self.next = None
    
    class Solution:
        def removeNthFromEnd(self, head: ListNode, n: int) -> ListNode:
            count = 1
            target = head
            temp = head
            while count < n:
                temp = temp.next
                count += 1
            if temp.next == None:
                return target.next
            else:
                temp = temp.next
            while temp.next != None:
                target = target.next
                temp = temp.next
            target_d = target.next
            target.next = target_d.next
            
            return head
            
    
    • recursive

      # Definition for singly-linked list.
      # class ListNode:
      #     def __init__(self, x):
      #         self.val = x
      #         self.next = None
      
      class Solution:
          def removeNthFromEnd(self, head: ListNode, n: int) -> ListNode:
              rec = self.helper(head, n)
              if rec == n:
                  return head.next
              return head
          
          def helper(self, head: ListNode, n: int) -> int:
              if head.next == None:
                  return 1
              rec = self.helper(head.next, n)
              if rec == n:
                  head.next = head.next.next
              return rec + 1
      

      递归做法,实际上这道题本质上必须遍历整个链表直到最后一个node,所以用递归的方法查看之后还剩多少个元素,如果正好是n的话,那么当前的结点(倒数第n+1个)的下一个结点(倒数第n个)就需要被删除。和另外一个方法比起来并不会增大memory的占用。runtime还更低(我猜是因为少了一个移动的指针)


    LC.83 Remove Duplicates from Sorted List

    Description

    Given a sorted linked list, delete all duplicates such that each element appear only once.

    Example 1:

    Input: 1->1->2
    Output: 1->2
    

    Example 2:

    Input: 1->1->2->3->3
    Output: 1->2->3
    

    Solution

    • straight solution (两个指针)

    • # Definition for singly-linked list.
      # class ListNode:
      #     def __init__(self, x):
      #         self.val = x
      #         self.next = None
      
      class Solution:
          def deleteDuplicates(self, head: ListNode) -> ListNode:
              node_a = head
              node_b = head
              if head == None:
                  return head
              while node_b.next != None:
                  if node_b.val != node_b.next.val:
                      node_a.next = node_b.next
                      node_a = node_a.next
                  node_b = node_b.next
              if not node_a == node_b:
                  node_a.next = node_b.next
              return head
      

      或者一个指针:

      class Solution:
          def deleteDuplicates(self, head: ListNode) -> ListNode:
              temp = head
              while temp != None and temp.next != None:
                  if temp.val == temp.next.val:
                      temp.next = temp.next.next
                  else:
                      temp = temp.next
              return head
      
    • 递归做法

      class Solution:
          def deleteDuplicates(self, head: ListNode) -> ListNode:
              if head == None or head.next == None:
                  return head
              if head.val == head.next.val:
                  return self.deleteDuplicates(head.next)
              else:
                  head.next = self.deleteDuplicates(head.next)
                  return head
      

    LC. 92 Reversed Linked List

    Reverse a linked list from position m to n. Do it in one-pass.

    Note: 1 ≤ mn ≤ length of list.

    Example:

    Input: 1->2->3->4->5->NULL, m = 2, n = 4
    Output: 1->4->3->2->5->NULL
    

    Solution

    • 直接从前往后走,只要还在reverse的范围内,看见一个拎出来一个,添加到旁边的翻转新链表的表头。所有需要翻转的都翻转完之后,把新的链表插在原来的链表里面

      class Solution(object):
          def reverseBetween(self, head, m, n):
              """
              :type head: ListNode
              :type m: int
              :type n: int
              :rtype: ListNode
              """
              holder = ListNode(-1)
              holder.next = head
              head = holder
              count = 1
              while count < m:
                  head = head.next
                  count += 1
              new = None
              while count < n+1:
                  temp = head.next.next
                  head.next.next = new
                  new = head.next
                  if count == m:
                      tail = new
                  head.next = temp
                  count += 1
              temp = head.next
              head.next = new
              tail.next = temp
              return holder.next
      
      

      在表的最前面加一个holder可以方便计数,并且corner case少了很多!!第17-20行是翻转表头的操作

    • 递归做法

      class Solution(object):
          def reverseBetween(self, head, m, n):
              """
              :type head: ListNode
              :type m: int
              :type n: int
              :rtype: ListNode
              """
              self.successor = None
              if m == 1:
                  return self.reverseHelper(head, n-m+1)
              head.next = self.reverseBetween(head.next, m-1, n-1)
              return head
                  
          def reverseHelper(self, head, m):
              if m == 1:
                  self.successor = head.next
                  return head
              new = self.reverseHelper(head.next, m-1)
              head.next.next = head
              head.next = self.successor
              return new
      

      是LC.206的变形,递归的时候加入一个变量k,reverse当前链表的前k个元素。递归现在还写得乱七八糟的!!


    LC. 61 Rotate List

    Given a linked list, rotate the list to the right by k places, where k is non-negative.

    Example 1:

    Input: 1->2->3->4->5->NULL, k = 2
    Output: 4->5->1->2->3->NULL
    Explanation:
    rotate 1 steps to the right: 5->1->2->3->4->NULL
    rotate 2 steps to the right: 4->5->1->2->3->NULL
    

    Example 2:

    Input: 0->1->2->NULL, k = 4
    Output: 2->0->1->NULL
    Explanation:
    rotate 1 steps to the right: 2->0->1->NULL
    rotate 2 steps to the right: 1->2->0->NULL
    rotate 3 steps to the right: 0->1->2->NULL
    rotate 4 steps to the right: 2->0->1->NULL
    

    Solution

    • 直接解:

      先数一下一共有多少个元素,再用总数减去模k的值求left rotate多少个。找到新的头元素,把tail和原来的头元素串起来就好了

      class Solution(object):
          def rotateRight(self, head, k):
              """
              :type head: ListNode
              :type k: int
              :rtype: ListNode
              """
              if not head:
                  return head
              count = 1
              key = head
              while key.next:
                  count += 1
                  key = key.next
              key.next = head
              k = count - k % count
              
              while k > 1:
                  head = head.next
                  k -= 1
              new = head.next
              head.next = None
              return new
      
    • 还可以用间隔k的两个指针,一旦走到头就重新回到head的方法,不需要显式地求list的长度。但这样复杂度显然变高了,模掉的那堆都得计算一遍


    LC. 143 Reorder List

    Given a singly linked list L: L0→L1→…→Ln-1→Ln,
    reorder it to: L0→LnL1→Ln-1→L2→Ln-2→…

    You may not modify the values in the list's nodes, only nodes itself may be changed.

    Example 1:

    Given 1->2->3->4, reorder it to 1->4->2->3.
    

    Example 2:

    Given 1->2->3->4->5, reorder it to 1->5->2->4->3.
    

    Solutions

    • 这题还蛮容易错的,主要是reverse list的时候不能反转原链表,这样正序的链表就没了;首先找到链表中点,然后反转后一半的链表,前一半的链表a和后一半的反转链表b交替插在一块儿就好了

      class Solution(object):
          def reorderList(self, head):
              """
              :type head: ListNode
              :rtype: None Do not return anything, modify head in-place instead.
              """
              if not head or not head.next:
                  return
              a = b = head
              move_a = False
              while b.next:
                  b = b.next
                  if move_a == True:
                      a = a.next
                      move_a = False
                  else:
                      move_a = True
              list_b = self.reverseList(a.next)
              a.next = None
              list_a = head
              while list_b:
                  a_temp = list_a.next
                  b_temp = list_b.next
                  list_a.next = list_b
                  list_b.next = a_temp
                  list_a = a_temp
                  list_b = b_temp
              return
          
          def reverseList(self, head):
              if not head.next:
                  return head
              new = self.reverseList(head.next)
              head.next.next = head
              head.next = None
              return new
      

      优化:

      第7-17行可以优化成如下,复杂度降了好多,我也不确定为什么,大概是更改变量的次数变少了。。

       while b.next.next:
                  b = b.next.next
                  a = a.next
                  if not b.next:
                      break
      
    • 感觉这道没必要用递归,因为每次都得找最尾端的元素,性价比很低 (?


    LC. 21. Merge Two Sorted Lists

    Merge two sorted linked lists and return it as a new list. The new list should be made by splicing together the nodes of the first two lists.

    Example:

    Input: 1->2->4, 1->3->4
    Output: 1->1->2->3->4->4、
    

    Solutions

    • 直接解(超级丑)

    • class Solution(object):
          def mergeTwoLists(self, l1, l2):
              """
              :type l1: ListNode
              :type l2: ListNode
              :rtype: ListNode
              """
              if not l1:
                  return l2
              if not l2:
                  return l1
              if l1.val <= l2.val:
                  head = l1
                  l1 = l1.next
              else:
                  head = l2
                  l2 = l2.next
              key = head
              while l1 and l2:
                  if l1.val <=l2.val:
                      key.next = l1
                      key = key.next
                      l1 = l1.next
                  else:
                      key.next = l2
                      key = key.next
                      l2 = l2.next
              if l1 or l2:
                  key.next = l1 if l1 else l2
              return head
      
    • 递归(似乎叫动态规划了这里)

      class Solution(object):
          def mergeTwoLists(self, l1, l2):
              """
              :type l1: ListNode
              :type l2: ListNode
              :rtype: ListNode
              """
              if not l1:
                  return l2
              if not l2:
                  return l1
              if l1.val <= l2.val:
                  l1.next = self.mergeTwoLists(l1.next, l2)
                  return l1
              else:
                  l2.next = self.mergeTwoLists(l1, l2.next)
                  return l2
      

    LC. 160. Intersection of Two Linked Lists

    Write a program to find the node at which the intersection of two singly linked lists begins.

    Notes:

    If the two linked lists have no intersection at all, return null.
    The linked lists must retain their original structure after the function returns.
    You may assume there are no cycles anywhere in the entire linked structure.
    Your code should preferably run in O(n) time and use only O(1) memory.

    Solutions

    • 一个超简洁的解法:

      class Solution(object):
          def getIntersectionNode(self, headA, headB):
              """
              :type head1, head1: ListNode
              :rtype: ListNode
              """
              if not headA or not headB:
                  return None
              
              a = headA
              b = headB
              while a != b:
                  a = headB if a == None else a.next
                  b = headA if b == None else b.next
              return a
      
      • 思路是a+b = b+a,如果遍历两遍,他们会同时到达终点,自动对齐

      • 第12行很重要,这和两个链表intersect的方式有关,如果只是一个node的val相同,这个语句是false的。必须后面是同一个链才是true

      • 第12行到14行的另外一种错误写法:

        if a.next == None:
            a.next = headB
        if b.next == None:
            b.next = headA
        a = a.next
        b = b.next
        

        原因是第2/4行会导致链表的终端不指向None,会形成一个环形链表,这样后到达的指针就出不来了!


    LC. 141. Linked List Cycle

    Given a linked list, determine if it has a cycle in it.

    To represent a cycle in the given linked list, we use an integer pos which represents the position (0-indexed) in the linked list where tail connects to. If pos is -1, then there is no cycle in the linked list.

    Example 1:

    Input: head = [3,2,0,-4], pos = 1
    Output: true
    Explanation: There is a cycle in the linked list, where tail connects to the second node.

    Solutions

    • 一个作弊解法:(which 我觉得肯定有毛病)

      class Solution(object):
          def hasCycle(self, head):
              """
              :type head: ListNode
              :rtype: bool
              """
              marker = ListNode(-1)
              if not head:
                  return False
              while head.next and not head.next == marker:
                  temp = head.next
                  head.next = marker
                  head = temp
              if not head.next:
                  return False
              return True
      

      走过的点就标记为走过,通过把它指向一个marker点。但这样链表就被损坏了

    • 龟兔赛跑的解法:一个指针以步长1移动,另一个以步长2移动。如果有环的话,fast指针一定会追上另外一个

      class Solution(object):
          def hasCycle(self, head):
              """
              :type head: ListNode
              :rtype: bool
              """
              try:
                  slow = head
                  fast = head.next
                  while not slow == fast:
                      slow = slow.next
                      fast = fast.next.next
                  return True
              except:
                  return False
      

      这里用try/except的写法写会更快,不必每次显式地检查是否有指针到达终点

    class Solution(object):
    def insertionSortList(self, head):
    """
    :type head: ListNode
    :rtype: ListNode
    """
    if not head:
    return head
    helper = ListNode(0)
    pre = helper

        while head:
            temp = head.next
            if pre.next and head.val < pre.next.val:
                pre = helper
            while pre.next and head.val >= pre.next.val:
                pre = pre.next
            head.next = pre.next
            pre.next = head
            head = temp
            
        return helper.next
    

    LC. 138 Copy List with Random Pointer

    A linked list is given such that each node contains an additional random pointer which could point to any node in the list or null.

    Return a deep copy of the list.

    Solution

    • 交替索引

      class Solution(object):
          def copyRandomList(self, head):
              """
              :type head: Node
              :rtype: Node
              """
              if not head:
                  return None
              helper = Node(0, head, None)
              while head.next:
                  new = Node(head.val, head.next, head.random)
                  head.next = new
                  head = head.next.next
              new = Node(head.val, None, head.random)
              head.next = new
              
              new_head = helper.next.next
              while new_head.next:
                  new_head.random = None if not new_head.random else new_head.random.next
                  new_head = new_head.next.next
              new_head.random = None if not new_head.random else new_head.random.next
                  
              head = helper.next
              helper.random = head.next
              new = Node(0, None, None)
              while head.next.next:
                  new.next = head.next
                  head.next = head.next.next
                  new = new.next
                  head = head.next
              new.next = head.next
              head.next = None
      
              return helper.random
      
    • keep an hash table for each node in the list: 原链表的每一个node索引到它的copy上,然后再次从头到位遍历原来的链表,写入新结点们的next和random

      class Solution(object):
          def copyRandomList(self, head):
              """
              :type head: Node
              :rtype: Node
              """
              if not head:
                  return None
              copy = dict()
              m = n = head
              while m:
                  copy[m] = Node(m.val, m.next, m.random)
                  m = m.next
              while n:
                  copy[n].next = copy.get(n.next)
                  copy[n].random = copy.get(n.random)
                  n = n.next
              return copy[head]
      

      需要注意的是,在第15/16行都用的是dict.get(key)而不是直接dict[key], 这是为了当key等于None的时候,返回default value None而不是报错。如果事先定义copy[None]=None的话,这两处也可以直接用dict[key]

      这种方法还有一个很trick的只遍历一次的写法,使用collections.defaultdict来访问(及创建)存在(或不存在)的结点

      class Solution(object):
          def copyRandomList(self, head):
              """
              :type head: Node
              :rtype: Node
              """
              copy = collections.defaultdict(lambda: Node(0, None, None))
              m = head
              copy[None] = None
              while m:
                  copy[m].val = m.val
                  copy[m].next = copy[m.next]
                  copy[m].random = copy[m.random]
                  m = m.next
              return copy(head)
      

      注意这里的12/13行是直接调用的方式,且在第9行定义了key=None的情况。这是因为现在的default是RandomNode(0)而不是None了


    LC. 142 Linked List Cycle II

    Given a linked list, return the node where the cycle begins. If there is no cycle, return null.

    To represent a cycle in the given linked list, we use an integer pos which represents the position (0-indexed) in the linked list where tail connects to. If pos is -1, then there is no cycle in the linked list.

    Solution

    • hash table that records the visited nodes

      class Solution(object):
          def detectCycle(self, head):
              """
              :type head: ListNode
              :rtype: ListNode
              """
              info = dict()
              m = head
              while m:
                  if not info.get(m):
                      info[m] = True
                  else:
                      return m
                  m = m.next
              return None
      
    • hare-tortoise method

      class Solution(object):
          def detectCycle(self, head):
              """
              :type head: ListNode
              :rtype: ListNode
              """
              fast = slow = helper = head
              try:
                  fast = fast.next.next
                  slow = slow.next
                  while not fast == slow:
                      fast = fast.next.next
                      slow = slow.next
                  while not helper == slow:
                      helper = helper.next
                      slow = slow.next
                  return helper
              except:
                  return None
      

      这里最重要的就是fast步长=2,slow=1。。。这样保证了fast恰好超slow一圈

    相关文章

      网友评论

          本文标题:链表 LC.19/83/92/61/143/21/160/141

          本文链接:https://www.haomeiwen.com/subject/azaxtctx.html