文章目录
注意:
- 这里的head是只存储地址。
实例讲解
prev = None # 前指针节点
curr = head # 当前指针节点
# 每次循环,都将当前节点指向它前面的节点,然后当前节点和前节点后移
while curr:
nextTemp = curr.next # 临时节点,暂存当前节点的下一节点,用于后移
curr.next = prev # 将当前节点指向它前面的节点
prev = curr # 前指针后移
curr = nextTemp # 当前指针后移
return prev
- 第四行的nextTemp = curr.next :(.next在等号右边)表示下一个节点的地址
- 第五行的curr.next (.next在等号左边)表示curr所指节点的地址
1 .链表基本功能
class ListNode:
"""
创建单个节点
"""
def __init__(self, x):
self.val = x
self.next = None
class MyLinkedList(object):
"""
单链表
"""
def __init__(self):
"""
头指针默认地址为空
长度为0
"""
self.head = None
self.length = 0
def is_empty(self):
"""判断链表是否为空"""
return self.head == None
def get(self, index):
"""
依据索引值获取指定节点值(下表从0开始)
:type index: int
:rtype: int
"""
if index < 0 or index >= self.length:
"""
索引值小于0或者索引值大于等于长度,返回-1
"""
return -1
p = self.head
for i in range(self.length):
if i == index:
return p.val
else:
p = p.next
def addAtHead(self, val):
"""头部添加元素"""
# 先创建一个保存val值的节点
node = ListNode(val)
# 将新节点的链接域next指向头节点,即self.head指向的位置
node.next = self.head
# 将链表的头self.head指向新节点
self.head = node
self.length += 1
def addAtTail(self, val):
"""尾部添加元素"""
node = ListNode(val)
# 先判断链表是否为空,若是空链表,则将self.head指向新节点
if self.is_empty():
self.head = node
# 若不为空,则找到尾部,将尾节点的next指向新节点
else:
cur = self.head
while cur.next:
"""找到最后一个节点"""
cur = cur.next
cur.next = node
self.length += 1
def addAtIndex(self, index, val):
"""
在指定为值添加索引,下标从0开始
思想:新建一个计数变量count
:type index: int
:type val: int
:rtype: None
"""
head = self.head
if index <= 0:
self.addAtHead(val)
elif index == self.length:
"""
索引值等于链表长度,讲节点加到链表的尾部
"""
self.addAtTail(val)
elif index < self.length and index > 0:
prev = head
count = 0
while count < index - 1:
count += 1
prev = prev.next
node = ListNode(val)
node.next = prev.next
prev.next = node
self.length += 1
def deleteNode(self, val):
"""
删除指定节点node ,从头遍历
:param node:
:return: 返回新链表q
"""
head = self.head
q = head
"""
p,q 用来 迭代
"""
p = q.next
if q.val == val:
"""如果头结点就是要删除的结"""
self.length -= 1
self.head = p
"""
要改变self.head,因为遍历的时候是从self.head开始的
"""
print('self.length:', self.length)
return p
while p:
if p.val == val:
q.next = p.next
self.length -= 1
print('lenth', self.length)
return q
else:
q = p
p = p.next
def deleteAtIndex(self, index):
"""
在指定位置删除
:type index: int
:rtype: None
"""
prev = self.head
if index == 0:
self.head = self.head.next
elif index > 0 and index < self.length:
# count从1开始
count = 1
while count < index:
prev = prev.index
prev.next = prev.next.next
self.length -= 1
def travel(self):
"""遍历链表"""
cur = self.head
while cur:
print('val:', cur.val)
cur = cur.next
print("")
def midNode(self):
"""
快慢指针,寻找中间节点
fast走两步,slow走一步
:return:返回mid的值
"""
head = self.head
if head is None or head.next is None:
"""没有节点,或者只有一个节点
"""
return head.val
fast = head
slow = head
while fast.next and fast.next.next:
"""
当为奇数个点的时候,fast.next会为空,跳出while循环
当为偶数个点的时候,fast.next.next会为空,跳出while循环
"""
fast = fast.next.next
slow = slow.next
if fast.next:
print('有偶数个点')
else:
print('有奇数个点')
return slow.val
def reverseList(self, head):
"""
反转一个单向链表
:param head:头部指针
:param prev:反转后的头结点
:return: 返回反转后的链表
"""
prev = None # 前指针节点
curr = head # 当前指针节点
# 每次循环,都将当前节点指向它前面的节点,然后当前节点和前节点后移
while curr:
nextTemp = curr.next # 临时节点,暂存当前节点的下一节点,用于后移
curr.next = prev # 将当前节点指向它前面的节点
prev = curr # 前指针后移
curr = nextTemp # 当前指针后移
return prev
# 递归思路:在return处调用自己(尾递归)
# if not head:
# return prev
#
# curr, head.next = head.next, prev # 新旧链表的两个方向同时前进
# return self.reverseList(curr, head)
def isPalindrome(self):
"""
判断回文链表的思想:
1.找到中间节点slow
2.把后半部分,逆序
3.把前半部分和后半部分比较
:type head: ListNode
:rtype: bool
"""
head = self.head
fast = head
slow = head
while fast and fast.next:
"""
当fast.next为None说明,fast已经在最后一个节点。也表明有奇数个点
当fast.next.next为空None,fast在倒数第二个节点。也表明有偶数个点
"""
fast = fast.next.next
slow = slow.next
prev = None # 前指针节点
curr = slow # 当前指针节点
# 每次循环,都将当前节点指向它前面的节点,然后当前节点和前节点后移
while curr:
nextTemp = curr.next # 临时节点,暂存当前节点的下一节点,用于后移
curr.next = prev # 将当前节点指向它前面的节点
prev = curr # 前指针后移
curr = nextTemp # 当前指针后移
while head and prev:
if head.val != prev.val:
return False
head = head.next
prev = prev.next
return True
def getIntersectionNode(self, headA, headB):
"""
相交链表,找到两个单链表相交的起始节点
例如:
listA = [4,1,8,4,5], listB = [5,0,1,8,4,5]
相交节点的值为8
:type head1, head1: ListNode
:rtype: ListNode
"""
"""
定义两个指针, 第一轮让两个到达末尾的节点指向另一个链表的头部, 最后如果相遇则为交点(在第一轮移动中恰好抹除了长度差)
两个指针等于移动了相同的距离, 有交点就返回, 无交点就是各走了两条指针的长度
"""
p = headA
q = headB
# 在这里第一轮体现在pA和pB第一次到达尾部会移向另一链表的表头, 而第二轮体现在如果pA或pB相交就返回交点, 不相交最后就是null == null
while p != q:
p = p.next if p else headB # 如果p成立,p = p.next,若不成立,p = headB
q = q.next if q else headA
return p
L = MyLinkedList()
print('----插入节点:-----')
L.addAtTail(1)
L.addAtTail(2)
L.addAtTail(3)
L.addAtTail(2)
L.addAtTail(1)
L.travel()
print('----寻找中间节点----')
A = L.midNode()
print(A)
print('----依据索引值获取节点的值-----')
b = L.get(2)
print(b)
print('----依据索引进行添加值(下标从0开始)----')
L.addAtIndex(2, 6)
L.travel()
print('长度:', L.length)
print('----删除节点(包括可以删除头部,尾部)----')
L.deleteNode(3)
print('----根据索引值删除指定节点(下标从0开始)----')
L.deleteAtIndex(0)
L.travel()
print('----判断是不是回文链表----')
L.travel()
print(L.isPalindrome())
# print(D)
2. 根据值删除链表中的节点
信息
请编写一个函数,使其可以删除某个链表中给定的(非末尾)节点,你将只被给定要求被删除的节点。
现有一个链表 – head = [4,5,1,9]
示例 1:
输入: head = [4,5,1,9], node = 5
输出: [4,1,9]
解释: 给定你链表中值为 5 的第二个节点,那么在调用了你的函数之后,该链表应变为 4 -> 1 -> 9.
示例 2:
输入: head = [4,5,1,9], node = 1
输出: [4,5,9]
解释: 给定你链表中值为 1 的第三个节点,那么在调用了你的函数之后,该链表应变为 4 -> 5 -> 9.
说明:
链表至少包含两个节点。
链表中所有节点的值都是唯一的。
给定的节点为非末尾节点并且一定是链表中的一个有效节点。
不要从你的函数中返回任何结果。
答案:
class ListNode:
def __init__(self, x):
self.val = x
self.next = None
class Solution:
def deleteNode(self, node):
"""
:type node: ListNode
:rtype: void Do not return anything, modify node in-place instead.
"""
node.val = node.next.val
node.next = node.next.next
3.反转一个单链表
信息
反转一个单链表。
示例:
输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL
进阶:
你可以迭代或递归地反转链表。你能否用两种方法解决这道题?
答案
def reverseList(self,head,prev=None):
"""
反转一个单向链表
:param head:头部指针
:param prev:反转后的头结点
:return: 返回反转后的链表
"""
while head:
curr = head
head = head.next
curr.next = prev
prev = curr
return prev
# 递归思路:在return处调用自己(尾递归)
# if not head:
# return prev
#
# curr, head.next = head.next, prev # 新旧链表的两个方向同时前进
# return self.reverseList(curr, head)
4.合并两个有序链表
信息
将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
示例:
输入:1->2->4, 1->3->4
输出:1->1->2->3->4->4
答案
class Solution:
def mergeTwoLists(self, l1: ListNode, l2: ListNode):
if l1 is None and l2 is None:
return None
# 新建了一个值为0的头部指针,所以我们在返回的时候要加.next(很巧妙),这样就不包含0这个节点了
new_list = ListNode(0)
pre = new_list
while l1 is not None and l2 is not None:
if l1.val < l2.val:
pre.next = l1
l1 = l1.next
else:
pre.next = l2
l2 = l2.next
pre = pre.next
if l1 is not None:
pre.next = l1
else:
pre.next = l2
return new_list.next
5.删除排序链表中的重复元素
信息
给定一个排序链表,删除所有重复的元素,使得每个元素只出现一次。
示例 1:
输入: 1->1->2
输出: 1->2
示例 2:
输入: 1->1->2->3->3
输出: 1->2->3
答案
class ListNode:
def __init__(self, x):
self.val = x
self.next = None
class Solution:
def deleteDuplicates(self, head: ListNode) -> ListNode:
"""
:type head: ListNode
:rtype: ListNode
"""
if head is None:
return None
h = ListNode(head.val)
current = h
flag = head.val
while head:
if flag == head.val:
head = head.next
else:
current.next = ListNode(head.val)
current = current.next
flag = head.val
head = head.next
return h
6.移除链表元素
信息
删除链表中等于给定值 val 的所有节点。
示例:
输入: 1->2->6->3->4->5->6, val = 6
输出: 1->2->3->4->5
def removeElements(self, head: ListNode, val: int) -> ListNode:
if head:
while head.val == val:
head = head.next
if head is None:
return head
q = head
p = q.next
while p:
if p.val == val:
q.next = p.next
else:
q = q.next
p = p.next
return head
7.环形链表
信息
给定一个链表,判断链表中是否有环。
为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。
示例 1:
输入:head = [3,2,0,-4], pos = 1
输出:true
解释:链表中有一个环,其尾部连接到第二个节点。
示例 2:
输入:head = [1,2], pos = 0
输出:true
解释:链表中有一个环,其尾部连接到第一个节点。
示例 3:
输入:head = [1], pos = -1
输出:false
解释:链表中没有环。
进阶
进阶:
你能用 O(1)(即,常量)内存解决此问题吗?
思路
- 1.快和慢两个指针,如果有环,则一定会相遇。一个指针走一步,一个指针走两步。
答案
class ListNode(object):
def __init__(self, x):
self.val = x
self.next = None
class Solution(object):
def hasCycle(self, head):
"""
:type head: ListNode
:rtype: bool
"""
if not head:
return False
p1 = head
p2 = head.next
while(1):
if p1 == None or p2 == None or p2.next == None:
return False
elif p1 == p2:
return True
else:
p1 = p1.next
p2 = p2.next.next