203.移除链表元素
1、题目:
https://leetcode.cn/problems/remove-linked-list-elements/
2、描述:
3、重点:
虚拟头节点的使用技巧
4、分析
# 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]:
# 创建虚拟头部节点以简化删除过程
dummy_head = ListNode(next = head)
# 遍历列表并删除值为val的节点
current = dummy_head
while current.next: # 最后一个节点的指针指向null,意味着已经遍历完了所有的节点
if current.next.val == val:
current.next = current.next.next
else:
current = current.next
return dummy_head.next
707.设计链表
1、题目
https://leetcode.cn/problems/design-linked-list/
2、虚拟头节点的使用
重点:
- 关注cur应该是dummy_head还是dummy_head.next
- 关注遍历何时结束
代码实现:
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
def get(self, index):
"""
获取下表为index的节点的值
:type index: int
:rtype: int
"""
# 首先判断index是否合法
if index < 0 or index >= self.size:
return -1
# 定义临时指针
cur = self.dummy_head.next # cur从头指针开始遍历
for i in range(index):
cur = cur.next
return cur.val
def addAtHead(self, val):
"""
将一个值为 val 的节点插入到链表中第一个元素之前。在插入完成后,新节点会成为链表的第一个节点
:type val: int
:rtype: None
"""
## 这里需要注意赋值顺序。
# # 新建一个节点,next为head,即dummy.next
# newnode = ListNode(val,next=self.dummy_head.next)
# # 更改dummy.next
# self.dummy_head.next = newnode
# 也可以直接写为
self.dummy_head.next = ListNode(val,self.dummy_head.next)
self.size += 1
def addAtTail(self, val):
"""
将一个值为 val 的节点追加到链表中作为链表的最后一个元素。
:type val: int
:rtype: None
"""
# 新节点
newnode = ListNode(val)
# 临时指针
cur = self.dummy_head
# for i in range(size):
# cur = cur.next
# 最后一个节点指向null,因此可以使用while
while cur.next:
cur = cur.next
cur.next = newnode
self.size += 1
def addAtIndex(self, index, val):
# 出错的地方!
"""
将一个值为 val 的节点插入到链表中下标为 index 的节点之前。
如果 index 等于链表的长度,那么该节点会被追加到链表的末尾。
如果 index 比长度更大,该节点将 不会插入 到链表中。
:type index: int
:type val: int
:rtype: None
"""
# 先判断index是否合法
if index < 0 or index > self.size: # 这里为什么是大于,因为index可以为size,添加到尾部
return
# 临时指针
cur = self.dummy_head
for i in range(index):
cur = cur.next
cur.next = ListNode(val,cur.next)
self.size += 1
def deleteAtIndex(self, index):
"""
如果下标有效,则删除链表中下标为 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
# 注意增加或者删除时,size的变化
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.反转链表
1、题目链接:
https://leetcode.cn/problems/reverse-linked-list/
2、重点
如果再定义一个新的链表,实现链表元素的反转,其实这是对内存空间的浪费。
其实只需要改变链表的next指针的指向,直接将链表反转 ,而不用重新定义一个新的链表,如图所示:
3、分析
常考的题
共两种解法
- 双指针法【先看懂这个】
- 递归法【再理解这个】
循环内部定义了temp指针
这里要注意的是,赋值顺序:
- 要先将cur赋值给pre
- 再将temp赋值给cur
# 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:
temp = cur.next
cur.next = pre
pre = cur
cur = temp
return pre
# 递归法
class Solution(object):
def reverseList(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
return self.reverse(head,None)
def reverse(self,cur,pre):
if cur == None:
return pre
temp = cur.next
cur.next = pre
return self.reverse(temp,cur)
24. 两两交换链表中的节点
1、链接:
https://leetcode.cn/problems/swap-nodes-in-pairs/
2、描述
3、重点分析
- 链表长度为奇数,则最后一个点不进行交换
- 若为偶数,正好可以两两交换
交换时,链表头节点发生了变化,所以需要dummy_head
4、代码
方法一:
在交换前,需要保存一下1和3!!!
# 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 swapPairs(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
dummyhead = ListNode(next=head) # 头节点
cur = dummyhead
while (cur.next!=None) and (cur.next.next!=None):
# 这个while也可以写为:
# while cur.next and cur.next.next:
# 注意结束条件,考虑奇数和偶数情况,注意先后顺序
temp = cur.next # 1
temp1 = cur.next.next.next # 3
cur.next = cur.next.next # cur->2
cur.next.next = temp # 2->1
cur.next.next.next = temp1 # 1->3 # 注意这里!不要犹豫
cur = cur.next.next # cur移动2
return dummyhead.next
方法二:递归,这里看的不是很懂
# 方法二 | 递归 不需要虚拟头节点
class Solution(object):
def swapPairs(self, head):
"""
两个指针进行两两交换
:type head: ListNode
:rtype: ListNode
"""
if head is None or head.next is None: # 终止条件:链表没有节点,或者链表中只有一个节点
return head
# 待翻转的两个节点
pre = head
cur = head.next
next1 = head.next.next
# 交换
cur.next = pre # 第二个指向第一个
# 交换后,原链表的头节点变成新链表第二个节点,原链表的第二个节点变成新链表的头节点
pre.next = self.swapPairs(next1)# 将以next为head的后续链表两两交换
return cur
19.删除链表的倒数第N个节点
1、链接:
https://leetcode.cn/problems/remove-nth-node-from-end-of-list/
2、描述
3、重点分析
既然是倒数第n个点,可以使用双指针
快指针先走n+1步,然后快慢指针同时走。
当快指针走到null时,慢指针的next便是需要删除的
- 删除节点需要前驱
- 倒数第n个节点可能是头节点,需要dummy_head
4、代码
class Solution(object):
def removeNthFromEnd(self, head, n):
"""
:type head: ListNode
:type n: int
:rtype: ListNode
"""
# 需要设置虚拟头节点,考虑要删除的点是头节点的情况 | 第一个错误点,没有考虑到头节点
dummyhead = ListNode(next=head)
fast,slow = dummyhead,dummyhead# 定义快慢指针
n += 1
for i in range(n): # 第二个错误点,fast移动n个点,用for循环,不是while
fast = fast.next
# while (n > 0) and fast:
# fast = fast.next # 快指针先走n+1步
# n -= 1
while fast:# 快慢指针一起走,直到fast指向none
fast = fast.next
slow = slow.next
slow.next = slow.next.next
return dummyhead.next
面试题 02.07. 链表相交
1、链接:
简单题~
https://leetcode.cn/problems/intersection-of-two-linked-lists-lcci/
2、描述
3、重点分析
4、代码
class Solution(object):
def getIntersectionNode(self, headA, headB):
"""
:type head1, head1: ListNode
:rtype: ListNode
"""
# 先求两个链表的长度
n = 0
m = 0
curA = headA
curB = headB
while curA:
curA = curA.next
n += 1
while curB:
curB = curB.next
m += 1
if m > n:
fast = headB
slow = headA
else:
fast = headA
slow = headB
for i in range(abs((m-n))):
fast = fast.next
while fast != slow:
fast = fast.next
slow = slow.next
return fast
142.环形链表II
1、链接:
https://leetcode.cn/problems/linked-list-cycle-ii/
2、描述
1、找到是否有环
2、去找环形的入口
3、重点分析
4、代码
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution(object):
def detectCycle(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
# 先判断有没有环
fast , slow = head , head
while (fast != None) and (fast.next != None):
# 可以写成:while fast and fast.next:
fast = fast.next.next # 移动两步
slow = slow.next # 移动一步
if fast == slow:
# 相遇 有环 -》寻找环的入口
index1 = head
index2 = fast
while index1 != index2:
index1 = index1.next
index2 = index2.next
return index1
# 没有环
return None