# Linked list

Single linked list: a linked list refers to a linear structure connected in series through pointers. Each node consists of two parts, one is the data field, the other is the pointer field (storing pointers to the next node), and the pointer field of the last node points to null (null pointer).

The entry node of the linked list is called the head node of the linked list, that is, head.

Double linked list: each node has two pointer fields, one pointing to the next node and the other pointing to the previous node.

Double linked list can be queried forward or backward.

Circular list: linked list.

Storage mode of linked list: the linked list is not continuously distributed in memory. The linked list is linked to each node in memory through the pointer of the pointer field. That is, the linked list is scattered on an address in memory.

Linked list definition:

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

# Remove linked list elements

Delete all nodes in the linked list equal to the given value val.

# Input: head = [1,2,6,3,4,5,6], val = 6 # Output: [1,2,3,4,5] def solution(head, val): pre_head = ListNode(-1) pre_head.next = head pre = pre_head while pre: if pre.next and pre.next.val == val: pre.next = pre.next.next else: pre = pre.next return pre_head.next

# Reverse linked list

Reverse a single linked list.

Example: input: 1 - > 2 - > 3 - > 4 - > 5 - > null output: 5 - > 4 - > 3 - > 2 - > 1 - > null

def solution(head): pre = None cur = head while cur: tmp = cur.next cur.next = pre pre = cur cur = tmp return pre

# Exchange the nodes in the linked list

Given a linked list, two adjacent nodes are exchanged, and the exchanged linked list is returned. You can't just change the value inside the node, but you need to actually exchange nodes.

Input: head = [1,2,3,4]

Output: [2,1,4,3]

def solution(head): pre = ListNode(-1) pre.next = head res = pre while pre.next and pre.next.next: cur = pre.next tmp = pre.next.next cur.next = tmp.next pre.next = tmp tmp.next = cur pre = pre.next.next return res.next

# Delete the penultimate node of the linked list

Give you a linked list, delete the penultimate node of the linked list, and return the head node of the linked list.

Advanced: can you try using one scan?

Input: head = [1,2,3,4,5], n = 2 output: [1,2,3,5]

def solution(head, n): pre = ListNode(0) pre.next = head slow, fast = pre, pre for i in range(n): fast = fast.next while fast: fast = fast.next slow = slow.next slow.next = slow.next.next return pre.next

# Linked list intersection

Given two (one-way) linked lists, determine whether they intersect and return the intersection. Note that the definition of intersection is based on the reference of the node, not the value of the node. In other words, if the k-th node of a linked list and the j-th node of another linked list are the same node (the references are exactly the same), the two linked lists intersect.

Input: listA = [4,1,8,4,5], listB = [5,0,1,8,4,5]

Output: Reference of the node with value = 8

def solution(heada, headb): cur_a, cur_b = heada, headb while cur_a != cur_b: cur_a = cur_a.next if cur_a else headb cur_b = cur_b.next if cur_b else heada return cur_a

# Circular linked list II

Given a linked list, return the first node from the linked list into the ring. If the linked list is acyclic, null is returned.

In order to represent the rings in a given linked list, the integer pos is used to represent the position where the tail of the linked list is connected to the linked list (the index starts from 0). If pos is - 1, there is no ring in the linked list.

def solution(head): slow, fast = head, head while fast and fast.next: slow = slow.next fast = fast.next.next if slow == fast: p = head q = slow while p != q: p = p.next q = q.next return p return None

# Design a linked list

Implement these functions in the linked list class:

get(index): get the value of the index node in the linked list. Returns - 1 if the index is invalid.

addAtHead(val): add a node with value val before the first element of the linked list. After insertion, the new node will become the first node in the linked list.

addAtTail(val): append the node with value val to the last element of the linked list.

addAtIndex(index,val): add a node with value val before the index node in the linked list. If the index is equal to the length of the linked list, the node will be attached to the end of the linked list. If the index is greater than the length of the linked list, the node will not be inserted. If the index is less than 0, the node is inserted in the header.

Delete atindex (index): if the index is valid, delete the index node in the linked list.

# Single linked list class ListNode: def __init__(self,val): self.val = val self.next = None class MyLinkedList: def __init__(self): self._head = ListNode(0) self._count = 0 def get(self, index): if 0 <= index < self._count: node = self._head for _ in range(index+1): node = node.next return node else: return -1 def addAHead(self, val): self.addAIndex(0, val) def addATail(self, val): self.addAIndex(self._count, val) def addAIndex(self, index, val): if index < 0: index = 0 elif index > self._count: return self._count += 1 add_node = ListNode(val) pre_node, cur_node = None, self._head for _ in range(index + 1): pre_node, cur_node = cur_node, cur_node.next else: pre_node.next, add_node.next = add_node, cur_node def delAIndex(self, index): if 0 <= index < self.count: self._count -= 1 pre_node, cur_node = None, self.head for _ in range(index+1): pre_node, cur_node = cur_node, cur_node.next else: pre_node, cur_node = cur_node.next, None # Double linked list # Compared with single linked list, Node adds prev attribute class Node: def __init__(self, val): self.val = val self.prev = None self.next = None class MyLinkedList: def __init__(self): self._head, self._tail = Node(0), Node(0) # Virtual node self._head.next, self._tail.prev = self._tail, self._head self._count = 0 # Number of nodes added def _get_node(self, index: int) -> Node: # When index is less than_ When count//2, use_ head lookup is faster, and vice versa_ tail faster if index >= self._count // 2: # Use prev to find forward node = self._tail for _ in range(self._count - index): node = node.prev else: # Use next to look back node = self._head for _ in range(index + 1): node = node.next return node def get(self, index: int) -> int: """ Get the value of the index-th node in the linked list. If the index is invalid, return -1. """ if 0 <= index < self._count: node = self._get_node(index) return node.val else: return -1 def addAtHead(self, val: int) -> None: """ Add a node of value val before the first element of the linked list. After the insertion, the new node will be the first node of the linked list. """ self._update(self._head, self._head.next, val) def addAtTail(self, val: int) -> None: """ Append a node of value val to the last element of the linked list. """ self._update(self._tail.prev, self._tail, val) def addAtIndex(self, index: int, val: int) -> None: """ Add a node of value val before the index-th node in the linked list. If index equals to the length of linked list, the node will be appended to the end of linked list. If index is greater than the length, the node will not be inserted. """ if index < 0: index = 0 elif index > self._count: return node = self._get_node(index) self._update(node.prev, node, val) def _update(self, prev: Node, next: Node, val: int) -> None: """ Update node :param prev: Relative to the previous node of the update :param next: Relative to the last node updated :param val: Node value to add """ # Count accumulation self._count += 1 node = Node(val) prev.next, next.prev = node, node node.prev, node.next = prev, next def deleteAtIndex(self, index: int) -> None: """ Delete the index-th node in the linked list, if the index is valid. """ if 0 <= index < self._count: node = self._get_node(index) # Count - 1 self._count -= 1 node.prev.next, node.next.prev = node.next, node.prev