链表的类型:
单链表 : 通过指针串联在一起的线性结构,每一个节点由两部分组成,一个是数据域一个是指针域(存放指向下一个节点的指针),最后一个节点的指针域指向null(空指针的意思)
双链表: 每一个节点有两个指针域,一个指向下一个节点,一个指向上一个节点。 双链表 既可以向前查询也可以向后查询
循环链表: 链表首尾相连
链表的存储:
数组是在内存中是连续分布的,但是链表在内存中可不是连续分布的;链表是通过指针域的指针链接在内存中各个节点
性能分析:
插入/删除(时间复杂度) | 查询(时间复杂度) | 试用场景 | |
数组 | O(n) | O(1) | 数据量固定,频繁查询,较少更改 |
链表 | O(1) | O(n) | 数据量不固定,频繁增删,较少查询 |
203. 移除链表元素
1. 设置一个虚拟头节点,这样可以避免遍历链表时,头节点被更改
2. 链表中是不存在完全删除一个节点的,而是让删除节点的前一个节点指向删除节点后面的一个节点,如果试用的是C++ 记得手动释放内存
3. 最后返回头节点时,return dummy_head -> next,因为真正的头节点可能被删除
# 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)
# set a temp pointer, to help iterate the linklist
cur = dummy_head
# find remove element position; cur.next != None is aviod we are acees a empty Node
while cur.next != None:
# if we find the element we want to remove
if cur.next.val == val:
# remove the address, let cur point to next next
cur.next = cur.next.next
else:
cur = cur.next
return dummy_head.next
707. 设计链表
- 使用虚拟头节点能很好的帮助实现每一个函数功能
- get函数: 判断index是否在valid的区域;current = dummy_head.next 因为我们for循环出来current的下一个值才是我们获取的目标值
- addAtHead函数: 让新头节点指向之前的头节点,让dummy_head指向新头节点;记得linklist的size + 1因为我们添加了新的节点进入链表当中
- addAtTail函数:跟上面一个实现方法相同,不过我们需要先遍历到链表尾部
- addAtIndex函数: 这里对于index合法边界的判断要注意 index > size 即可,因为这样可以保证我们可以在链表尾部插入元素
- deleteAtIndex函数: 先检查index合法性,再去遍历到index位置通过操作链表节点的地址从而让需要删除节点跟前节点失去链接,达到删除的目的
class ListNode():
def __init__(self,val=0,next=None):
self.val = val
self.next = next
class MyLinkedList(object):
def __init__(self):
self.dummy_head = ListNode() # create a vitrual head
self.size = 0 # define linklist size
def get(self, index):
"""
:type index: int
:rtype: int
"""
# makesure is not empty linklist
if index < 0 or index >= self.size:
return -1
current = self.dummy_head.next
# iterate the linklist,find which element we want
for _ in range(index):
current = current.next
# after the for loop we find index element, return it
return current.val
def addAtHead(self, val):
"""
:type val: int
:rtype: None
"""
# create a new node
newNode = ListNode(val=val)
# temp head
current = self.dummy_head
# add new head
newNode.next = current.next
current.next = newNode
# since we add a node into our linklist
self.size += 1
def addAtTail(self, val):
"""
:type val: int
:rtype: None
"""
# creat dummy head
current = self.dummy_head
newNode = ListNode(val=val)
# find the tail
while current.next is not None:
current = current.next
# find the correct position to insert new Node
current.next = newNode
# add node into our linklist size += 1
self.size += 1
def addAtIndex(self, index, val):
"""
:type index: int
:type val: int
:rtype: None
"""
# determine the index is correct range
if index < 0 or index > self.size:
return
# create dummy head
current = self.dummy_head
# creat new node
newNode = ListNode(val=val)
# find index position
for _ in range(index):
current = current.next
# add index element
newNode.next = current.next
current.next = newNode
self.size += 1
def deleteAtIndex(self, index):
"""
:type index: int
:rtype: None
"""
# detemine index is valid range
if index < 0 or index >= self.size:
return
# create dummyhead
current = self.dummy_head
# find the element we want to remove
for _ in range(index):
current = current.next
# delet the node
current.next = current.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. 反转列表(面试高频)
- 定义一个prev指针存储为None
- 创建虚拟头节点,避免在遍历的时候修改我们原始头节点
- 在遍历中使用temp去保存current的下一个节点地址
- 改变链表方向时,先让current.next 指向我们prev指针,也就是上一个节点元素
- 移动指针一定是要prev先走,如果current指针先移动的话会导致prev和current都指向同一个节点,从而导致失去前一个节点的地址从而无法顺利反转列表
最后返回一定是返回prev指针,因为prev指针是我们新的头节点位置(原始链表的尾部)
# 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
"""
dummy_head = ListNode(next=head)
current = dummy_head.next
# create prev pointer to save the previous node
prev = None
# iterate the linklist
while current:
# save current.next node addres
temp = current.next
current.next = prev
# move prev first; if we move current first, then prev will point to same node as current
prev = current
# move current
current = temp
# return prev, this is our new head node
return prev