leetcode链接: https://leetcode.cn/problems/reverse-linked-list/description/
题目要求: 给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。
解题思路一:迭代
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
"""
# 初始化一个指向None的指针prev,它将用来作为新链表的头部
prev = None
# 当前节点指针指向头节点
curr = head
# 遍历链表
while curr:
# 临时保存当前节点的下一个节点,因为接下来需要修改当前节点的next指针
next_temp = curr.next
# 反转当前节点的指针,指向prev
curr.next = prev
# 将prev和curr都向前移动一步
prev = curr
curr = next_temp
# 当遍历完成时,prev将会指向新的头节点
return prev
解题思路二:递归
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
class Solution:
def reverseList(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
# 递归基准情况
if head is None or head.next is None:
return head
# 递归地反转下一个节点
reversed_head = self.reverseList(head.next)
# 将当前节点接到反转部分的尾部
head.next.next = head
head.next = None
# 返回新的头节点
return reversed_head
leetcode链接: https://leetcode.cn/problems/reverse-linked-list-ii/description/
题目要求: 给你单链表的头指针 head 和两个整数 left 和 right ,其中 left <= right 。请你反转从位置 left 到位置 right 的链表节点,返回 反转后的链表 。
解题思路一:迭代
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
class Solution:
def reverseBetween(self, head, left, right):
"""
:type head: ListNode
:type left: int
:type right: int
:rtype: ListNode
"""
# 特殊情况:链表为空或不需要反转
if not head or left == right:
return head
# 初始化指针
dummy = ListNode(0, head)
prev = dummy
# 移动prev到反转部分的前一个节点
for _ in range(left - 1):
prev = prev.next
# 开始反转的第一个节点
curr = prev.next
# 进行局部反转
for _ in range(right - left):
temp = curr.next
curr.next = temp.next
temp.next = prev.next
prev.next = temp
# 返回头节点,如果反转包括了头节点,则返回新头节点
return dummy.next
解题思路二:一趟扫描完成反转
class ListNode(object):
def __init__(self, val=0, next=None):
self.val = val
self.next = next
class Solution(object):
def reverseBetween(self, head, left, right):
"""
:type head: ListNode
:type left: int
:type right: int
:rtype: ListNode
"""
# 特殊情况处理:如果链表为空或不需要反转,则直接返回原链表
if not head or left == right:
return head
# 创建一个哑节点(dummy node),其next指向头节点head。
# 这有助于简化对链表头部修改的处理。
dummy = ListNode(0)
dummy.next = head
# 初始化pre指针,用于定位到left的前一个位置
pre = dummy
for _ in range(left - 1):
pre = pre.next
# 初始化curr和next指针,用于实际的反转操作
curr = pre.next
next = curr.next
# 执行反转操作
for _ in range(right - left):
# 将next节点移动到反转部分的起始位置
curr.next = next.next
next.next = pre.next
pre.next = next
# 更新next指针到curr的下一个节点
next = curr.next
# 返回哑节点的下一个节点作为新的头节点
return dummy.next
leetcode链接: https://leetcode.cn/problems/reverse-nodes-in-k-group/description/
题目要求: 给你链表的头节点 head ,每 k 个节点一组进行翻转,请你返回修改后的链表。
k 是一个正整数,它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。
你不能只是单纯的改变节点内部的值,而是需要实际进行节点交换。
解题思路一:
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
class Solution:
def reverseKGroup(self, head, k):
"""
:type head: ListNode
:type k: int
:rtype: ListNode
"""
if head is None or k == 1:
return head
# 创建哑节点
dummy = ListNode(0)
dummy.next = head
pre = dummy
# 计算链表长度
count = 0
while head:
count += 1
head = head.next
while count >= k:
cur = pre.next
nex = cur.next
# 翻转 k 个节点
for _ in range(1, k):
cur.next = nex.next
nex.next = pre.next
pre.next = nex
nex = cur.next
# 移动 pre 到下一组
pre = cur
count -= k
return dummy.next
解题思路二:一个只用 O(1) 额外内存空间
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
class Solution:
def reverseKGroup(self, head, k):
"""
:type head: ListNode
:type k: int
:rtype: ListNode
"""
# 创建哑节点
dummy = ListNode(0)
dummy.next = head
pre = dummy
# 计算链表长度
length = 0
while head:
length += 1
head = head.next
# 按照长度进行分组反转
while length >= k:
curr = pre.next
nex = curr.next
# 反转k个节点
for _ in range(1, k):
curr.next = nex.next
nex.next = pre.next
pre.next = nex
nex = curr.next
# 更新pre为下一组的前一个节点
pre = curr
# 减去已处理的节点数
length -= k
return dummy.next
leetcode链接: https://leetcode.cn/problems/palindrome-linked-list/description/
题目要求:
给你一个单链表的头节点 head ,请你判断该链表是否为回文链表。如果是,返回 true ;否则,返回 false 。
解题思路一:
class ListNode(object):
def __init__(self, val=0, next=None):
self.val = val
self.next = next
class Solution(object):
def isPalindrome(self, head):
"""
:type head: ListNode
:rtype: bool
"""
# 找到链表中点
fast, slow = head, head
while fast and fast.next:
fast = fast.next.next
slow = slow.next
# 反转链表后半部分
prev = None
while slow:
temp = slow.next
slow.next = prev
prev = slow
slow = temp
# 比较前半部分和反转后的后半部分
left, right = head, prev
while right:
if left.val != right.val:
return False
left = left.next
right = right.next
return True
解题思路二: O(n) 时间复杂度和 O(1) 空间复杂
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
class Solution:
def isPalindrome(self, head):
"""
:type head: ListNode
:rtype: bool
"""
if head is None or head.next is None:
return True
# 快慢指针找中点
slow, fast = head, head
while fast and fast.next:
slow = slow.next
fast = fast.next.next
# 反转链表后半部分
prev = None
while slow:
temp = slow.next
slow.next = prev
prev = slow
slow = temp
# 比较前后半部分
left, right = head, prev
while right:
if left.val != right.val:
return False
left = left.next
right = right.next
return True
leetcode链接: https://leetcode.cn/problems/merge-two-sorted-lists/description/
题目要求: 将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
解题思路一:
class ListNode(object):
def __init__(self, val=0, next=None):
self.val = val
self.next = next
class Solution(object):
def mergeTwoLists(self, list1, list2):
"""
:type list1: Optional[ListNode]
:type list2: Optional[ListNode]
:rtype: Optional[ListNode]
"""
# 创建哑节点
dummy = ListNode(0)
curr = dummy
# 合并两个链表
while list1 and list2:
if list1.val < list2.val:
curr.next = list1
list1 = list1.next
else:
curr.next = list2
list2 = list2.next
curr = curr.next
# 添加剩余的节点
if list1:
curr.next = list1
elif list2:
curr.next = list2
# 返回合并后的链表的头节点
return dummy.next
leetcode链接: https://leetcode.cn/problems/sort-list/description/
题目要求: 给你链表的头结点 head ,请将其按 升序 排列并返回 排序后的链表 。
解题思路一:迭代
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
class Solution:
def sortList(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
if not head or not head.next:
return head
# 计算链表长度
length = 0
current = head
while current:
length += 1
current = current.next
# 初始化哑节点
dummy = ListNode(0, head)
# 每次将链表分割成多个长度逐渐增加的子链表
subLength = 1
while subLength < length:
prev, curr = dummy, dummy.next
while curr:
# 分割出两个子链表
head1 = curr
for i in range(1, subLength):
if curr.next:
curr = curr.next
else:
break
head2 = curr.next
curr.next = None
curr = head2
for i in range(1, subLength):
if curr and curr.next:
curr = curr.next
else:
break
succ = None
if curr:
succ = curr.next
curr.next = None
# 合并两个子链表
merged = self.merge(head1, head2)
prev.next = merged
while prev.next:
prev = prev.next
curr = succ
subLength <<= 1
return dummy.next
def merge(self, head1, head2):
"""
合并两个排序好的链表
"""
dummy = ListNode(0)
tail = dummy
while head1 and head2:
if head1.val < head2.val:
tail.next = head1
head1 = head1.next
else:
tail.next = head2
head2 = head2.next
tail = tail.next
tail.next = head1 if head1 else head2
return dummy.next
解题思路二:归并排序( O(1) 的空间复杂度,时间复杂度是 O(n log n))
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
class Solution:
def sortList(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
# 递归结束条件,链表为空或只有一个节点时返回
if not head or not head.next:
return head
# 使用快慢指针法找到链表中点
slow, fast = head, head.next
while fast and fast.next:
fast = fast.next.next
slow = slow.next
# 分割链表为两部分
mid = slow.next
slow.next = None
# 对两个子链表递归排序
left = self.sortList(head)
right = self.sortList(mid)
# 合并两个排序好的链表
return self.merge(left, right)
def merge(self, l1, l2):
"""
合并两个排序好的链表
"""
dummy = ListNode(0)
tail = dummy
# 合并过程
while l1 and l2:
if l1.val < l2.val:
tail.next = l1
l1 = l1.next
else:
tail.next = l2
l2 = l2.next
tail = tail.next
# 将剩余部分链接到排序好的链表后面
tail.next = l1 if l1 else l2
return dummy.next
leetcode链接: https://leetcode.cn/problems/merge-k-sorted-lists/description/
题目要求: 给你一个链表数组,每个链表都已经按升序排列。
请你将所有链表合并到一个升序链表中,返回合并后的链表。
解题思路一:
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
class Solution:
def mergeKLists(self, lists):
"""
:type lists: List[ListNode]
:rtype: ListNode
"""
if not lists:
return None
if len(lists) == 1:
return lists[0]
mid = len(lists) // 2
# 递归分治合并
l1 = self.mergeKLists(lists[:mid])
l2 = self.mergeKLists(lists[mid:])
return self.mergeTwoLists(l1, l2)
def mergeTwoLists(self, l1, l2):
"""
合并两个有序链表
"""
dummy = ListNode(0)
tail = dummy
while l1 and l2:
if l1.val < l2.val:
tail.next = l1
l1 = l1.next
else:
tail.next = l2
l2 = l2.next
tail = tail.next
tail.next = l1 if l1 else l2
return dummy.next
leetcode链接: https://leetcode.cn/problems/linked-list-cycle/description/
题目要求: 给你一个链表的头节点 head ,判断链表中是否有环。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。注意:pos 不作为参数进行传递 。仅仅是为了标识链表的实际情况。
如果链表中存在环 ,则返回 true 。 否则,返回 false 。
解题思路一:快慢指针(O(1)(即,常量)内存)
# Definition for singly-linked list.
# 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 or not head.next:
return False
# 初始化两个指针:慢指针和快指针
slow = head
fast = head.next
# 遍历链表
while slow != fast:
# 如果快指针到达链表尾部(或其下一个节点为None),说明没有环
if not fast or not fast.next:
return False
# 慢指针移动一步,快指针移动两步
slow = slow.next
fast = fast.next.next
# 如果快慢指针相遇,则说明链表中有环
return True
leetcode链接: https://leetcode.cn/problems/linked-list-cycle-ii/
题目要求:
解题思路一:快慢指针(空间复杂度是 O(1))
# 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
"""
if not head or not head.next:
return None
slow, fast = head, head
# 判断链表是否有环
while True:
if not fast or not fast.next:
return None
slow = slow.next
fast = fast.next.next
if slow == fast:
break
# 找到环的起始节点
fast = head
while slow != fast:
slow = slow.next
fast = fast.next
return slow
leetcode链接: https://leetcode.cn/problems/intersection-of-two-linked-lists/description/
题目要求: 给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null 。
解题思路一:时间复杂度 O(m + n) 、仅用 O(1) 内存
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution(object):
def getIntersectionNode(self, headA, headB):
"""
:type head1, head1: ListNode
:rtype: ListNode
"""
if not headA or not headB:
return None
pointerA, pointerB = headA, headB
# 当两个指针不相等时继续遍历
while pointerA != pointerB:
# 如果指针 A 到达末尾,则跳到链表 B 的头部
pointerA = pointerA.next if pointerA else headB
# 如果指针 B 到达末尾,则跳到链表 A 的头部
pointerB = pointerB.next if pointerB else headA
# 如果两个链表相交,pointerA 和 pointerB 会在相交节点相遇
# 如果不相交,最终会同时为 None
return pointerA
leetcode链接: https://leetcode.cn/problems/remove-nth-node-from-end-of-list/
题目要求: 给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。
解题思路一:一趟扫描实现
# 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 removeNthFromEnd(self, head, n):
"""
:type head: ListNode
:type n: int
:rtype: ListNode
"""
# 初始化一个哑节点,用于处理边界情况
dummy = ListNode(0, head)
fast = slow = dummy
# 快指针先走 n 步
for _ in range(n):
fast = fast.next
# 快慢指针一起走
while fast.next:
slow = slow.next
fast = fast.next
# 删除倒数第 n 个节点
slow.next = slow.next.next
# 返回新的头节点
return dummy.next
leetcode链接: https://leetcode.cn/problems/reorder-list/description/
题目要求:
给定一个单链表 L 的头节点 head ,单链表 L 表示为:
L0 → L1 → … → Ln - 1 → Ln
请将其重新排列后变为:
L0 → Ln → L1 → Ln - 1 → L2 → Ln - 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 reorderList(self, head):
"""
:type head: ListNode
:rtype: None Do not return anything, modify head in-place instead.
"""
if not head or not head.next:
return
# 找到中点
slow, fast = head, head
while fast and fast.next:
slow = slow.next
fast = fast.next.next
# 反转后半部分链表
prev, curr = None, slow
while curr:
curr.next, prev, curr = prev, curr, curr.next
# 重新组合链表
first, second = head, prev
while second.next:
first.next, first = second, first.next
second.next, second = first, second.next