(二刷)代码随想录算法训练营day3 | 203.移除链表元素,707.设计链表,206.反转链表

链表

  1. 与数组存储不同,链表在内存中不是连续分布的
  2. 复杂度分析:
    • 查询:  O(n)
    • 增删:O(1)
  3. 特别注意ListNode的定义:(python)
class ListNode():
    def __init__(self, val, next = None):
        self.val = val
        self.next = next

203.移除链表元素

利用dummy_head来统一之后的解法

# 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 removeElements(self, head, val):
        """
        :type head: ListNode
        :type val: int
        :rtype: ListNode
        """
        
        dummy_head = ListNode(next=head)
        curr = dummy_head
        
        while curr.next != None:
            if curr.next.val == val:
                curr.next = curr.next.next
                
            else:
                curr = curr.next 
            #这里二刷时出错,对于head = [7,7,7,7], val = 7 这种情况来讲,curr就暂时不能向后                                            
            #移动,因为更新后的curr会是7 == val,此时出错。
                
        return dummy_head.next

707.设计链表 (medium)

二刷依旧没能自己写出来,继续。。。

  1. 要熟悉ListNode的定义方式,由于dummyHead只用作索引,所以其值val初始化为多少都可以。
  2. 不只是这道题,所有的题目都应该最先考虑极端情况,比如本题的index是否合理。
  3. 边界问题。这是一个很常见的问题,最好的处理方式就是考虑一个小的数(loop次数)来用笔来画一下或是“运行”一下,这样就很清晰什么时候需要停止。
  4. 可能第一次写的时候不会想到复用的情况,比如addAtHead(), addAtTail()是可以通过更通用的addAtIndex()来实现的,这是可以的。其原理也是一样的。
  5. 题解:(单向链表,双向链表待做...
class Node():
    def __init__(self, val, next=None):
        self.val = val
        self.next = next


class MyLinkedList(object):

    def __init__(self):
        self.dummyHead = Node(0) 
        self.size = 0

    def get(self, index):
        """
        :type index: int
        :rtype: int
        """
        if index < 0 or index >= self.size:
            return -1
        
        curr = self.dummyHead
        while index > 0:
            curr = curr.next
            index -= 1
            
        return curr.next.val
        

    def addAtHead(self, val):
        """
        :type val: int
        :rtype: None
        """
        self.addAtIndex(0, val)
        

    def addAtTail(self, val):
        """
        :type val: int
        :rtype: None
        """
        self.addAtIndex(self.size, val)
        

    def addAtIndex(self, index, val):
        """
        :type index: int
        :type val: int
        :rtype: None
        """
        if index < 0 or index > self.size:
            return 
        
        newNode = Node(val)
        
        curr = self.dummyHead
        while index > 0:
            curr = curr.next
            index -= 1
        
        temp = curr.next
        curr.next = newNode
        newNode.next = temp
        
        self.size += 1
        

    def deleteAtIndex(self, index):
        """
        :type index: int
        :rtype: None
        """
        if index < 0 or index >= self.size:
            return
        
        curr = self.dummyHead
        while index > 0:
            curr = curr.next
            index -= 1
            
        curr.next = curr.next.next
        self.size -= 1
        


# Your MyLinkedList object will be instantiated and called as such:
# obj = MyLinkedList()
# param_1 = obj.get(index)
# obj.addAtHead(val)
# obj.addAtTail(val)
# obj.addAtIndex(index,val)
# obj.deleteAtIndex(index)

206.反转链表

二刷依旧是下面的问题,继续。。。

  1. 对于解题的逻辑没有问题,问题在于对于“虚拟头节点”的思想没有灵活运用:这里虽然也要定义一个节点来使得head有指向,但是这里定义的并不是dummyHead,而是一个Null,是一个链表最终的收尾。
  2. 节点和指针的概念:head是头节点,prev是指针,因此最后返回prev,而不是head(head返回的是节点的值)。
  3. 对于为什么返回prev而不是head,即使二刷时对于这种解释我也不是很舒服,经过仔细研究整理了自己的理解(不一定严谨,但是现阶段可以这么理解):
    1. 首先动手画图一步一步运行到最后会发现,while循环停止时prev指向head(此时链表的头节点),但注意的是head是节点,prev是指针!
    2. (最开始没有画图的理解)大部分的链表题目都会定义cur = head来操作链表,此时cur就是指向head节点的指针(此时head是节点),然后经多while cur:来进行一些列的操作,如果配合dummyHead的话最终会返回dummyHead.next,这样就能解释为什么是返回prev了。如果是这样的话,像这道题并没有定义cur = head,但是实际的做法就是将head当作指针来操作(while head:),但是要明确head本身是头节点,最终返回的依旧是prev
  4. 题解:(代码上半部分是错的,下半部分是正确的)
# 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 reverseList(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        
        prev = None
        
        while head.next:
            temp = head.next
            head.next = prev
            prev = head
            head = temp
            
        return head
            
        


# 上面的问题在于返回的是节点的值


# 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 reverseList(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        
        prev = None
        
        while head: # why not head.next? Because even though head.next = None, it's still ok for reversing.
            temp = head.next
            head.next = prev
            prev = head
            head = temp
            
        return prev
            
        

总结:

  1. 配合画图来帮助理顺处理逻辑。

  2. 链表一定要分清节点和指针的概念 new ListNode()是真实存在的一个节点, head = new ListNode() 相当于 head指针指向了一个真实的节点, node = head, 相当于node和head同时指向了这个真实的节点。(day3 知识点)

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