代码随想录算法训练营第三天 | 链表理论基础、203. 移除链表元素、707. 设计链表、206. 反转链表

75 阅读2分钟

链表理论基础

单向链表

双向链表

20200806194559317

循环链表

20200806194629603

链表的存储

  • 数组是在内存中是连续分布的,但是链表在内存中可不是连续分布的。
  • 链表是分散在内存中的节点,通过指针链接起来组成的数据结构

链表节点的定义

class ListNode:
  def __init__(self, val, next=None):
    self.val = val
    self.next = next

链表的操作

删除节点:O(1)

20200806195114541

添加节点:O(1)

20200806195134331

查找节点:O(n)

从头节点开始遍历,直到找到需要的下标或者数值

适用场景

适合频繁增删,较少查找的场景。


203. 移除链表元素

代码随想录视频讲解

代码随想录文章讲解

dummy_head

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next# Time complexity: O(N)
# Space complexity: O(1)
class Solution:
    def removeElements(self, head: Optional[ListNode], val: int) -> Optional[ListNode]:
        if head is None:
            return head
        dummy_head = ListNode(0, head)
        cur = dummy_head
        while cur.next:
            if cur.next.val == val:
                cur.next = cur.next.next
            else:
                cur = cur.next
        return dummy_head.next

原链表

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next# Time complexity: O(N)
# Space complexity: O(1)
class Solution:
    def removeElements(self, head: Optional[ListNode], val: int) -> Optional[ListNode]:
        if head is None:
            return head
        while head is not None and head.val == val:
            head = head.next
        cur = head
        while cur is not None and cur.next:
            if cur.next.val == val:
                cur.next = cur.next.next
            else:
                cur = cur.next
        return head

707. 设计链表

代码随想录视频讲解

代码随想录文章讲解

dummy_head + 单向链表

class Node:
    def __init__(self, val=0, next=None):
        self.val= val
        self.next= next
​
​
class MyLinkedList:
    def __init__(self):
      # dummy_head
        self.head= Node(0)
        self.length= 0
    
    # Time complexity: O(index)
    def get(self, index: int) -> int:
        if index < 0 or index > self.length - 1:
            return -1
        else:
            cur= self.head
            for i in range(index+1):
                cur= cur.next
            return cur.val
          
    # Time complexity: O(1)
    def addAtHead(self, val: int) -> None:
        self.addAtIndex(0, val)
    
    # Time complexity: O(N)
    def addAtTail(self, val: int) -> None:
        self.addAtIndex(self.length, val)
    
    # Time complexity: O(index)
    def addAtIndex(self, index: int, val: int) -> None:
        if index < 0:
            index= 0
        elif index > self.length:
            return
        else:
            cur= self.head
            for _ in range(index):
                cur= cur.next
            new_node= Node(val, cur.next)
            cur.next= new_node
            self.length += 1
    
    # Time complexity: O(index)
    def deleteAtIndex(self, index: int) -> None:
        if index < 0 or index > self.length - 1:
            return
        else:
            cur= self.head
            for _ in range(index):
                cur= cur.next
            next_next_node= cur.next.next
            cur.next= next_next_node
            self.length -= 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)

双向链表

class Node:
    def __init__(self, val=0, prev=None, next=None):
        self.val = val
        self.next = next
        self.prev = prev
​
​
class MyLinkedList:
    def __init__(self):
        self.head = Node(0)
        self.tail = Node(0)
        self.head.next = self.tail
        self.tail.prev = self.head
        self.length = 0
​
    # Time complexity: O(min(k,N−k))
    def get(self, index: int) -> int:
        if index < 0 or index > self.length - 1:
            return -1
        else:
            if index+1 <= self.length - index:
                cur = self.head
                for i in range(index+1):
                    cur = cur.next
            else:
                cur = self.tail
                for i in range(self.length - index):
                    cur = cur.prev
            return cur.val
​
    # Time complexity: O(1)
    def addAtHead(self, val: int) -> None:
        new_node = Node(val, self.head, self.head.next)
        self.head.next.prev = new_node
        self.head.next = new_node
        self.length += 1
​
    # Time complexity: O(1)
    def addAtTail(self, val: int) -> None:
        new_node = Node(val, self.tail.prev, self.tail)
        self.tail.prev.next = new_node
        self.tail.prev = new_node
        self.length += 1
​
    # Time complexity: O(min(k,N−k))
    def addAtIndex(self, index: int, val: int) -> None:
        if index < 0:
            index = 0
        elif index > self.length:
            return
        else:
            if index <= self.length - index + 1:
                cur = self.head
                for _ in range(index):
                    cur = cur.next
            else:
                cur = self.tail
                for _ in range(self.length - index + 1):
                    cur = cur.prev
            new_node = Node(val, cur, cur.next)
            cur.next.prev = new_node
            cur.next = new_node
            self.length += 1
​
    # Time complexity: O(min(k,N−k))
    def deleteAtIndex(self, index: int) -> None:
        if index < 0 or index > self.length - 1:
            return
        else:
            if index <= self.length - index - 1:
                cur = self.head
                for _ in range(index):
                    cur = cur.next
                next_next_node = cur.next.next
                cur.next = next_next_node
                next_next_node.prev = cur
            else:
                cur = self.tail
                for _ in range(self.length - index - 1):
                    cur = cur.prev
                prev_prev_node = cur.prev.prev
                cur.prev = prev_prev_node
                prev_prev_node.next = cur
            self.length -= 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. 反转链表

代码随想录视频讲解

代码随想录文章讲解

prev, cur双指针反转

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next# Time complexity: O(N)
# Space complexity: O(1)
class Solution:
    def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
        if head is None or head.next is None:
            return head
        prev = None
        cur = head
        while cur:
            next_node = cur.next
            cur.next = prev
            prev = cur
            cur = next_node
        return prev

递归法

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next# Time complexity: O(N)
# Space complexity: O(N)
class Solution:
    def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
        if head is None or head.next is None:
            return head
​
        def reverse(prev, cur):
            if cur is None:
                return prev
            next_node = cur.next
            cur.next = prev
            return reverse(cur, next_node)
​
        return reverse(None, head)