重塑解题思路,直击82题:“删掉重复,只留不重”
2023-11-30 08:47:24
一、剖析题目,明确目标
82题要求我们从一个排序链表中删除所有重复元素,只保留原始链表中没有重复出现的数字。为了更好地理解题目要求,我们可以将问题分解成以下几个关键点:
- 排序链表: 给定链表已经按照特定顺序排列,这为我们提供了便利。
- 删除重复元素: 需要从链表中删除所有重复出现的元素,只保留不重复的数字。
- 只保留不重复: 这意味着,当遇到重复元素时,我们需要将其全部删除,不能保留任何重复的元素。
二、审视问题,多角度思考
在理解了题目要求后,我们需要对问题进行审视,以便找到合适的解题思路。我们可以从以下几个角度进行思考:
- 哨兵节点: 为了方便处理链表的删除操作,我们可以在链表开头添加一个哨兵节点,哨兵节点不包含任何数据,仅作为链表的起始标志。
- 双指针法: 我们可以使用两个指针来遍历链表,一个指针指向当前元素,另一个指针指向当前元素的前一个元素。这样,当遇到重复元素时,我们可以使用前一个指针来删除当前元素,并继续遍历链表。
- 递归法: 我们可以使用递归来解决这个问题。在递归函数中,我们可以首先判断当前元素是否与前一个元素相同。如果相同,则继续递归,删除当前元素及其之后的重复元素。如果不相同,则将当前元素添加到结果链表中,并继续递归。
三、综合考虑,选择最优方案
在考虑了多种解题思路后,我们需要综合考虑它们的优缺点,以便选择最优方案。哨兵节点可以简化链表的删除操作,但需要额外的空间复杂度。双指针法的时间复杂度和空间复杂度都较低,但需要额外的代码来处理重复元素的删除。递归法的时间复杂度和空间复杂度都较高,但不需要额外的代码来处理重复元素的删除。
经过综合考虑,我们选择双指针法作为82题的最优解。双指针法的时间复杂度为O(n),空间复杂度为O(1),不需要额外的空间来存储哨兵节点或递归栈。
四、具体实现,逐行剖析
def delete_duplicates(head):
"""
删除排序链表中的所有重复元素,只保留原始链表中没有重复出现的数字。
Args:
head: 链表头节点
Returns:
链表头节点
"""
# 如果链表为空或只有一个元素,则直接返回
if head is None or head.next is None:
return head
# 创建哨兵节点
dummy = ListNode(0, head)
# 定义两个指针,pre和cur
pre = dummy
cur = head
# 遍历链表
while cur:
# 如果当前元素与前一个元素相同,则将pre和cur同时向后移动
if cur.val == pre.val:
pre.next = cur.next
# 否则,将pre指针向后移动一位,并将cur指针移动到下一个元素
else:
pre = pre.next
cur = cur.next
# 返回哨兵节点的下一个节点,即链表的头节点
return dummy.next
在上面的代码中,我们首先判断链表是否为空或只有一个元素,如果是,则直接返回。然后,我们创建哨兵节点,并定义两个指针,pre和cur。pre指针指向当前元素的前一个元素,cur指针指向当前元素。我们遍历链表,如果当前元素与前一个元素相同,则将pre和cur指针同时向后移动。否则,将pre指针向后移动一位,并将cur指针移动到下一个元素。最后,我们返回哨兵节点的下一个节点,即链表的头节点。
五、总结升华,融会贯通
82题的解题过程体现了编程的精髓,那就是多角度思考和综合考虑。我们不仅要理解题目要求,还要从不同的角度审视问题,以便找到最优解。同时,我们还需要综合考虑各种解题方案的优缺点,以便做出最优选择。
82题的解题思路可以应用到许多其他问题中。例如,我们可以使用双指针法来解决环形链表的检测问题,也可以使用递归法来解决二叉树的遍历问题。