1. 移除链表元素(203)
用虚拟头节点, 首先值得注意的是python中创建虚拟头节点的方式
dummy_head = ListNode(next=head)
这行代码的作用是创建一个虚拟的头节点(dummy head),并将其 next
指针指向链表的真实头节点 head
。
用current这个临时指针进行遍历, 因为头指针如果改了就找不到链表了
另外值得注意的是要确定current.next不能为空值,否则下一步current.next.next就是对空取next,是不合法操作
还有一点就是current存储dummy_head的指针而不是dummy_head.next, 这是因为要删除时, 要知道这个节点的前节点和后节点,并且让前节点指向后一个节点. 那么如果知道current, 能删除的是current.next而不是current本身(因为无法知道前一个节点)
最后return的是dummy_head.next, 虚拟节点后面的节点是新链表的节点, 而不是原来的head节点(有可能已经被删除)
用虚拟节点的好处是节省了代码量,如果不用虚拟节点要考虑删除的节点是否为头节点, 如果删除的是头节点,需要head = head -> next, 而如果不是头节点, 处理方法则与虚拟节点处理方法类似, 即cur = cur -> next
dummy_head = ListNode(next = head)
current = dummy_head
while(current.next):
if current.next.val == val:
current.next = current.next.next
else:
current = current.next
return dummy_head.next
2. 设计链表(707)
首先对链表进行初始化
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()
self.size = 0
2.1 获取第n个节点的值
首先确定合法的index取值范围, 可以发现 index<0 或者index>size-1的时候不合法
本道题是要获取第n个节点的值, 那么也就是获取cur点的value值, 当cur为0的时候, 获取的就是head节点对应的值, 所以head是dummyhead.next, 所以cur = dummyhead.next
这里while也可以改写为for循环: for i in range(index), 可以省略index -= 1的操作
def get(self, index):
"""
:type index: int
:rtype: int
"""
if index < 0 or index>= self.size:
return -1
cur = self.dummy_head.next
while index:
cur = cur.next
index -= 1
return cur.val
2.2 头部插入节点
在插入节点要注意顺序, 如果先写dummyhead.next = newnode, 会出现当再写newnode.next = dummyhead.next的时候找不到节点的问题(这里是头节点尚且还可以用head表示,但是如果是在n节点中插入会出现丢失节点的情况)
所以要先写后者再写前者
在python中似乎不存在这样的问题, 指定dummyhead下一个点的next点是当前dummyhead.next(即head节点)即可, 实际上也包含了从右边到左边的顺序
另外要注意的是增删节点时要注意更新size的大小
def addAtHead(self, val):
"""
:type val: int
:rtype: None
"""
self.dummy_head.next = ListNode(val, self.dummy_head.next)
self.size += 1
2.3 尾部插入节点
这里似乎cur是dummyhead还是dummyhead.next都不影响, 因为最后终止的条件和index没有关系,判断尾部的条件是cur.next = null(在python中应该是none)
当找到了尾部的节点, 让新节点的next为none即可
插入节点以后更新size值
def addAtTail(self, val):
"""
:type val: int
:rtype: None
"""
cur = self.dummy_head
while cur.next :
cur = cur.next
cur.next = ListNode(val)
self.size += 1
2.4 第n个节点前插入节点
涉及到在第n个节点插入节点的问题, 首先要考虑边界的问题
其次, 要想在第n个节点前插入新节点, 还得知道n-1个节点是什么, 也就是说插入的n节点是cur.next, n=0时, current.next是head节点, 那么cur= dummyhead
所以将newnode的next设置为cur.next, 将cur.next设置为newnode即可
注意设置的顺序, 在python中即 将新节点的next节点设置为cur.next, 并且让cur的next指向新节点即可
增删以后记得更新size的值
def addAtIndex(self, index, val):
"""
:type index: int
:type val: int
:rtype: None
"""
if index < 0 or index > self.size:
return
cur = self.dummy_head
while index:
cur = cur.next
index -= 1
cur.next = ListNode(val, cur.next)
self.size += 1
2.5 删除第n个节点
删除第n个节点, 需要注意越界问题
删除第n个节点的时候, 需要知道第n个节点的前后两个节点, 也就是current 和 current.next.next, 也就是n对应的是current.next, 所以n=0是head, current=dummyhead
删除第n个节点就是直接让current节点指向current.next.next节点, 也就是current.next = cureent.next.next
增删记得结尾需要更新size
def deleteAtIndex(self, index):
"""
:type index: int
:rtype: None
"""
if index < 0 or index >= self.size:
return
cur = self.dummy_head
for i in range(index):
cur = cur.next
cur.next = cur.next.next
self.size -= 1
3.反转链表(206)
3.1 双指针法
首先初始化cur和pre, cur指向head, pre指向head之前, head翻转以后成为尾节点, 指向null, 所以把pre初始化为none
然后就是将cur指向pre完成反转, 这里注意几个问题:
1. 终止条件: 当pre到了尾节点, cur指向null的时候, 就不需要再反转了, 遍历应该已经结束. 也就是说当cur为空的时候, 应该结束遍历
所以结束的条件应该是cur == null
2. 先要用temp存下cur.next的值, 再进行反转, 否则cur指向pre以后, 无法得知cur反转之前的下一个节点的指针, 无法继续
3. 移动时, 应该先移动pre, 再移动cur, 因为如果先移动cur, 无法用pre=cur得知cur之前所在的位置了,pre就无法到达cur之前所在位置
4. 反转完成以后, pre成为新的链表的头节点, 所以直接return pre
class Solution(object):
def reverseList(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
cur = head
pre = None
while cur:
temp = cur.next
cur.next = pre
pre = cur
cur = temp
return pre
3.2 递归
这里递归由双指针简化和演变而来, 主要是省略了移动cur和pre的操作, 而直接用递归完成. 首先用if写清楚递归的结束条件, 即在cur为null的时候return pre, 即结束递归
其次要完成pre->cur的反转, 先用一个临时指针temp记录反转之前的cur.next, 便于下一步递归的连续. 然后用cur.next = pre完成反转.
在下一步的递归中, 将cur作为pre, 将temp作为cur, 完成递归
初始递归条件为cur为head, pre为none, 在主函数reverselist的返回值写入
def reverseList(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
def reverse(cur, pre):
if cur == None:
return pre
temp = cur.next
cur.next = pre
return reverse(temp, cur)
return reverse(head, None)