文章目录
- 合并两个有序链表
- 删除排序链表中的重复元素 1
- 删除排序链表中的重复元素 2
- 环形链表1
- 环形链表2
- 相交链表
- 反转链表
合并两个有序链表
将两个升序链表合并为一个新的 升序 链表并返回。
新链表是通过拼接给定的两个链表的所有节点组成的。
示例 1:
输入:
l
1
{l1}
l1 = [1,2,4],
l
2
{l2 }
l2= [1,3,4]
输出:[1,1,2,3,4,4] 以列表 表示每个节点的value
示例 2:
输入:
l
1
{l1}
l1 = [],
l
2
{l2}
l2 = []
输出:[] 表示没有节点 None
示例 3:
输入:l1 = [], l2 = [0]
输出:[0] 表示有一个value为0的节点
提示:
两个链表的节点数目范围是 [0, 50]
-100 <= Node.val <= 100
l1 和 l2 均按 升序排列
python实现:双指针
# Definition for singly-linked list.
# class ListNode: # 预定义好的 直接用就行
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def mergeTwoLists(self, list1: Optional[ListNode], list2: Optional[ListNode]) -> Optional[ListNode]: # ListNode or None
if not list1 and not list2:
return None # [] 代表空节点
elif not list1 or not list2:
return list1 if list1 else list2
#
header = None
p = None
while list1 and list2:
if list1.val <= list2.val:
if header is None:
header = list1
p = list1
else:
p.next = list1
p = list1
list1 = list1.next
else:
if header is None:
header = list2
p = list2
else:
p.next = list2
p = list2
list2 = list2.next
if list1:
p.next = list1
elif list2:
p.next = list2
return header
java实现:
删除排序链表中的重复元素 1
给定一个已排序的链表的头 head , 删除重复的后继元素,使每个元素只出现一次 。返回 已排序的链表 。
示例 1:
输入:head = [1,1,2]
输出:[1,2]
示例 2:
输入:head = [1,1,2,3,3]
输出:[1,2,3]
python实现:递归算法
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def deleteDuplicates(self, head: Optional[ListNode]) -> Optional[ListNode]:
if head is None or head.next is None:
return head
# 至少两个节点
cur = head
if cur.val == cur.next.val:
cur.next = cur.next.next
return self.deleteDuplicates(head)
else:
cur.next = self.deleteDuplicates(cur.next)
return head
java实现:
删除排序链表中的重复元素 2
给一个已排序的链表的头 head , 删除原始链表中所有 重复数字的节点 ,返回该链表 。
重点:已排序
示例 1:
输入:head = [1,2,3,3,4,4,5]
输出:[1,2,5]
示例 2:
输入:head = [1,1,1,2,3]
输出:[2,3]
python实现: 递归解决
- 情况1:删除头节点重复的部分,继续递归处理剩下的部分;
- 情况2:保留头节点,继续处理剩下的部分
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def deleteDuplicates(self, head: Optional[ListNode]) -> Optional[ListNode]:
if head is None or head.next is None:
return head
# 至少两个节点
cur = head
if cur.val == cur.next.val: # 要删除头节点
move = cur.next.next
while move and cur.val == move.val: # 移动到不相等的节点
move = move.next
return self.deleteDuplicates(move)
else:
cur.next = self.deleteDuplicates(cur.next) # 保留头节点
return head
同一段程序,多次提交,耗时和击败用户比率会不同;所以不用在乎这个击败比率。
java实现:
pending
环形链表1
给一个链表的头节点 head ,判断链表中是否有环。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。存在环 ,则返回 true 。 否则,返回 false 。
以下pos不作为参数
示例 1:
输入:head = [3,2,0,-4], pos = 1
输出:true
示例 2:
输入:head = [1,2], pos = 0
输出:true
解释:链表中有一个环,其尾部连接到第一个节点。
示例 3:
输入:head = [1], pos = -1
输出:false
解释:链表中没有环。
进阶:你能用 O(1) 空间复杂度解决此问题吗?
python实现:
# 辅助空间 + 循环
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def hasCycle(self, head: Optional[ListNode]) -> bool:
temp = []
cur = head
while cur:
temp.append(cur)
if cur.next in temp: # python内置方法也慢
return True
cur = cur.next
return False
# 双指针 一快 一慢 空间复杂度O(1)
# 快走两步 慢走一步 会在环内相遇
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def hasCycle(self, head: Optional[ListNode]) -> bool:
if head is None:
return False
slow_ptr = head # 一次走一步
fast_ptr = head # 一次走两步
while fast_ptr.next and fast_ptr.next.next:
slow_ptr = slow_ptr.next
fast_ptr = fast_ptr.next.next
if fast_ptr is slow_ptr:
return True
return False
java双指针
环形链表2
给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。
pos不传参,且不允许修改链表
示例 1:
输入:head = [3,2,0,-4], pos = 1
输出:返回索引为 1 的链表节点
示例 2:
输入:head = [1,2], pos = 0
输出:返回索引为 0 的链表节点
示例 3:
输入:head = [1], pos = -1
输出:返回 null
解释:链表中没有环。
python实现:
# 辅助空间 + 循环
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def detectCycle(self, head: Optional[ListNode]) -> Optional[ListNode]:
if head is None:
return None
temp = []
cur = head
while cur:
temp.append(cur)
if cur.next in temp:
return cur.next
cur = cur.next
return None
# 双指针 一快一慢 空间复杂度O(1)
# 快指针移动2步
# 漫指针移动1步
# 在环中相遇后,慢指针重置到head指针
# 然后两个指针均移动一步,直到再次相遇,即找到入环的节点
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def detectCycle(self, head: Optional[ListNode]) -> Optional[ListNode]:
if head is None:
return None
slow_ptr = head
fast_ptr = head
has_circle = False
while fast_ptr.next and fast_ptr.next.next:
slow_ptr = slow_ptr.next
fast_ptr = fast_ptr.next.next
if fast_ptr is slow_ptr:
has_circle = True
break
if has_circle:
# 重置慢指针为head
slow_ptr = head
# 两个指针均移动一步,直到相遇
while slow_ptr is not fast_ptr:
slow_ptr = slow_ptr.next
fast_ptr = fast_ptr.next
# 相遇则为入环节点
return fast_ptr
return None
优化前后时间对比:
java实现:
相交链表
给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null 。
你能否设计一个时间复杂度 O(m + n) 、仅用 O(1) 内存的解决方案?
m,n 分别为链表A B的节点数。
图示两个链表在节点 c1 开始相交:
示例 1:
输入:listA = [4,1,8,4,5], listB = [5,6,1,8,4,5]
skipA = 2, skipB = 3 intersectVal = 8,
输出:node 8 对象
示例 2:
输入:listA = [1,9,1,2,4], listB = [3,2,4], skipA = 3, skipB = 1 intersectVal = 2,
输出:node 2
示例 3:
输入:listA = [2,6,4], listB = [1,5], skipA = 3, skipB = 2 intersectVal = 0,
输出:null
python 实现:
双指针 循环移动 直至相遇
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> Optional[ListNode]:
if headA is None or headB is None:
return None
pa = headA
pb = headB
while pa is not pb:
pa = pa.next if pa else headB
pb = pb.next if pb else headA
return pa
也可以计算链表的长度差值,较长的链表指针移动长度差个步子。
反转链表
给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。
示例 1:
输入:head = [1,2,3,4,5]
输出:[5,4,3,2,1]
示例 2:
输入:head = [1,2]
输出:[2,1]
示例 3:
输入:head = []
输出:[]
进阶:链表可以选用迭代或递归方式完成反转。你能否用两种方法解决这道题?
python实现:
在这里插入代码片
java实现: