重要知识点:
1. 链表的定义: 链表是一种通过指针串联在一起的线性结构,每一个节点由两部分组成,一个是数据域一个是指针域(存放指向下一个节点的指针),最后一个节点的指针域指向null(空指针的意思)
2. 链表的形式: 单链表, 双链, 循环链。 自己之前接触单链表和循环链表比较多点。
3. 链表数据的储存方式: 非连续的, 通过节点的指针串起来的。 和数组有本质的区别
4. 链表和数组的对比:链表增加/删除节点时间复杂度 O(1),数组 O(n), 因为数组要向前覆盖后面的所有数据, 链表只需要改变指针的指向。链表查询的时间复杂度 O(n), 数组O(1)。 因为链表储存空间不连续, 需要从 head 开始往后查找。 链表和数组有各自的优劣势。
203.移除链表元素:
思路:循环链表的所有节点,如果看到一个节点的值等于特定值, 需要讲该节点前一个节点的指针, 指向该节点后一个指针。 但是因为单链表往前退一个节点很麻烦, 所以每次检查当前节点的下一个节点的值是不是等于特定值。 如果是的话, 就让当前节点的指针指向下一个节点的下一个节点。 这样需要对head 的值比较小心, 如果当前节点从head 开始就会忽略掉head值等于特定值的情况。 所以我的做法是给链表的head 前面在增加一个node(node的值无所谓)。循环从新增的node 开始就行了。
难点: 开头的节点
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def removeElements(self, head: Optional[ListNode], val: int) -> Optional[ListNode]:
start_node = ListNode(0)
start_node.next = head
current_node = start_node
while current_node:
next_node = current_node.next
if next_node and next_node.val == val:
current_node.next = next_node.next
else:
current_node = current_node.next
return start_node.next
707.设计链表
思路: 要求定义 myLinkedList 类, 然后按照要求写 member function 就可以了, 都是些基本的增加,删除,查找元素。
难点: 有些特殊情况需要考虑,例如 head 是 None 的时候如何增加元素。 这里我是做了特殊处理, 但是应该也可以考虑上一题的处理开头的思路把特殊情况变为一般情况。
class MyLinkedList:
def __init__(self, head: ListNode = None):
self.head = head
def get(self, index: int) -> int:
tmp_node = self.head
i = 0
while tmp_node:
if i == index:
return tmp_node.val
i += 1
tmp_node = tmp_node.next
return -1
def addAtHead(self, val: int) -> None:
new_node = ListNode(val)
new_node.next = self.head
self.head = new_node
return
def addAtTail(self, val: int) -> None:
if not self.head:
self.addAtHead(val)
return
new_node = ListNode(val)
tmp_node = self.head
while tmp_node:
if not tmp_node.next:
tmp_node.next = new_node
break
tmp_node = tmp_node.next
return
def addAtIndex(self, index: int, val: int) -> None:
new_node = ListNode(val)
if index==0: self.addAtHead(val)
i = 1
tmp_node = self.head
while tmp_node and i<=index:
if i == index:
new_node.next = tmp_node.next
tmp_node.next = new_node
i += 1
tmp_node = tmp_node.next
return
def deleteAtIndex(self, index: int) -> None:
if index == 0: self.head = self.head.next
tmp_node = self.head
i = 1
while tmp_node and tmp_node.next and i <= index:
if i == index:
tmp_node.next = tmp_node.next.next
tmp_node = tmp_node.next
i += 1
return
206.反转链表:
思路: 单链表不容易向前循环。 因此处理的时候先定义了一个 prev_node = None (记录反正链表的head), 然后从 head 开始循环链表, 先用 tmp_node 记录当前节点, 然后 head 往后移动, 然后 tmp_node 节点的指针指向 prev_node, 最后 prev_node 更新到 tmp_node. 这里head 要先往后跑一个在改tmp_node 的指针。 要不然head 就跳出input 链表了。
难点: 先跑head 再改指针。
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
prev_node = None
while head:
tmp_node = head
head = head.next
tmp_node.next = prev_node
prev_node = current_node
return prev_node