参考文献 代码随想录
一、移除链表元素
给你一个链表的头节点 head
和一个整数 val
,请你删除链表中所有满足 Node.val == val
的节点,并返回 新的头节点 。
示例 1:
输入:head = [1,2,6,3,4,5,6], val = 6 输出:[1,2,3,4,5]
示例 2:
输入:head = [], val = 1 输出:[]
示例 3:
输入:head = [7,7,7,7], val = 7 输出:[]
使用的是虚拟头结点,为什么要使用呢?因为统一操作,如果不适用虚拟头结点,当删除的节点为头结点的时候,就要进行一个判断,这个判断使用if还是while呢,如果使用的是if则会发生这样的情况,假设所以的节点都是要删除的节点,那么当你删除第一个头结点的时候,有会出现另外一个头结点,这是使用if的时候,所以要使用while进行判断,而使用虚拟头结点,则会省下这样的情况,进而统一了操作规则
# Definition for singly-linked list. # class ListNode(object): # def __init__(self, val=0, next=None): # self.val = val # self.next = next 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) current_head = dummy_head while current_head.next: if current_head.next.val == val: current_head.next = current_head.next.next else: current_head = current_head.next return dummy_head.next
二、设计链表
你可以选择使用单链表或者双链表,设计并实现自己的链表。
单链表中的节点应该具备两个属性:val
和 next
。val
是当前节点的值,next
是指向下一个节点的指针/引用。
如果是双向链表,则还需要属性 prev
以指示链表中的上一个节点。假设链表中的所有节点下标从 0 开始。
实现 MyLinkedList
类:
MyLinkedList()
初始化MyLinkedList
对象。int get(int index)
获取链表中下标为index
的节点的值。如果下标无效,则返回-1
。void addAtHead(int val)
将一个值为val
的节点插入到链表中第一个元素之前。在插入完成后,新节点会成为链表的第一个节点。void addAtTail(int val)
将一个值为val
的节点追加到链表中作为链表的最后一个元素。void addAtIndex(int index, int val)
将一个值为val
的节点插入到链表中下标为index
的节点之前。如果index
等于链表的长度,那么该节点会被追加到链表的末尾。如果index
比长度更大,该节点将 不会插入 到链表中。void deleteAtIndex(int index)
如果下标有效,则删除链表中下标为index
的节点。
示例:
输入 ["MyLinkedList", "addAtHead", "addAtTail", "addAtIndex", "get", "deleteAtIndex", "get"] [[], [1], [3], [1, 2], [1], [1], [1]] 输出 [null, null, null, null, 2, null, 3] 解释 MyLinkedList myLinkedList = new MyLinkedList(); myLinkedList.addAtHead(1); myLinkedList.addAtTail(3); myLinkedList.addAtIndex(1, 2); // 链表变为 1->2->3 myLinkedList.get(1); // 返回 2 myLinkedList.deleteAtIndex(1); // 现在,链表变为 1->3 myLinkedList.get(1); // 返回 3
解法1:单链表,最容易出错的地方就是,删除或者是添加,先把要删除或者是添加节点的下一个指向,然后在把当前添加的节点的上一个的next指向添加节点
class ListNode(object): 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 # 记录节点的长度 def get(self, index): """ :type index: int :rtype: int """ if index < 0 or index >= self.size: # 因为index时从零开始的 return -1 current = self.dummy_head.next for i in range(index): current = current.next # index -= 1 return current.val def addAtHead(self, val): """ :type val: int :rtype: None """ self.dummy_head.next = ListNode(val, self.dummy_head.next) self.size += 1 def addAtTail(self, val): """ :type val: int :rtype: None """ current = self.dummy_head while current.next: # 要想找到尾部元素,那么它的下一个节点的值为null current = current.next current.next = ListNode(val) self.size += 1 def addAtIndex(self, index, val): """ :type index: int :type val: int :rtype: None """ if index < 0 or index > self.size: return -1 current = self.dummy_head for i in range(index): current = current.next current.next = ListNode(val, current.next) self.size += 1 def deleteAtIndex(self, index): """ :type index: int :rtype: None """ if index < 0 or index >= self.size: return -1 current = self.dummy_head for i in range(index): current =current.next 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)
解法2:双链表
class ListNode: def __init__(self, val=0, prev=None, next=None): self.val = val self.prev = prev self.next = next class MyLinkedList: def __init__(self): self.head = None self.tail = None self.size = 0 def get(self, index: int) -> int: if index < 0 or index >= self.size: return -1 if index < self.size // 2: current = self.head for i in range(index): current = current.next else: current = self.tail for i in range(self.size - index - 1): current = current.prev return current.val def addAtHead(self, val: int) -> None: new_node = ListNode(val, None, self.head) if self.head: self.head.prev = new_node else: self.tail = new_node self.head = new_node self.size += 1 def addAtTail(self, val: int) -> None: new_node = ListNode(val, self.tail, None) if self.tail: self.tail.next = new_node else: self.head = new_node self.tail = new_node self.size += 1 def addAtIndex(self, index: int, val: int) -> None: if index < 0 or index > self.size: return if index == 0: self.addAtHead(val) elif index == self.size: self.addAtTail(val) else: if index < self.size // 2: current = self.head for i in range(index - 1): current = current.next else: current = self.tail for i in range(self.size - index): current = current.prev new_node = ListNode(val, current, current.next) current.next.prev = new_node current.next = new_node self.size += 1 def deleteAtIndex(self, index: int) -> None: if index < 0 or index >= self.size: return if index == 0: self.head = self.head.next if self.head: self.head.prev = None else: self.tail = None elif index == self.size - 1: self.tail = self.tail.prev if self.tail: self.tail.next = None else: self.head = None else: if index < self.size // 2: current = self.head for i in range(index): current = current.next else: current = self.tail for i in range(self.size - index - 1): current = current.prev current.prev.next = current.next current.next.prev = current.prev 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)
三、反转链表
给你单链表的头节点 head
,请你反转链表,并返回反转后的链表。
示例 1:
输入:head = [1,2,3,4,5] 输出:[5,4,3,2,1]
示例 2:
输入:head = [1,2] 输出:[2,1]
示例 3:
输入:head = [] 输出:[]
解法1:双指针,例如 [1, 2, 3, 4, 5] ---> [5, 4, 3, 2, 1],原来1是头结点,后来5是头结点,该如何调换呢,就是1.next = 2.next = 3.next = 4.next = 5.next = null 变成 5.next = 4.next = 3.next = 2.next = 1.next = null,定义一个pre = null,cur = head,tmp = cur.next,为什么要定义tmp,因为,当你把cur.nest 指向pre时,cur.next 就与原来的链表断开了,所以要使用tmp来存储省下的链表,以便右面的cur和pre移动,该如何移动cur和pre,直接pre = cur, cur = tmp,为什么呢?因为cur它是pre下一个,而tmp保存的是cur的下一个,为什么要先写pre = cur, cur =tmp,而不能写cur =tmp,pre = cur,因为,如果你写的是后者,那么cur现在存储的是cur移动的下一个位置,而你现在有把它赋值给pre,说明,pre移动的不是下一个位置,而是下下个位值,所以要先移动pre的位置,然后在移动cur的位置,然后while条件是什么呢?因为cur是每个节点,cur只有指向了none的时候,说明已经改变完了。
# 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 """ pre = None cur = head while cur: tmp = cur.next cur.next = pre pre = cur cur = tmp return pre # 为什么返回的是pre,而不是cur,因为cur它已经指向了none,而pre指向的是所有节点的最后一个
解法2:递归
# 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 reverse(self, cur, pre): if cur == None: return pre tmp = cur.next cur.next = pre return self.reverse(tmp, cur) # 必须返回 def reverseList(self, head): """ :type head: ListNode :rtype: ListNode """ return self.reverse(head, None)