在 LeetCode 上征服#83:告别重复,拥抱有序!
2023-09-15 17:24:47
驯服链表中的重复元素:LeetCode #83 算法之旅
认识我们的对手:LeetCode #83
在数字世界的浩瀚海洋中,重复就像一位不速之客,潜伏在我们精心构建的数据结构中,破坏着代码的整洁性和效率。对于任何一位严肃的程序员来说,驯服这些重复元素都是一项必备技能。LeetCode 上的#83 题就是这样一个考验,它要求我们从一个排序链表中删除所有重复元素。准备好踏上算法之旅,在这个过程中,我们将磨练我们的技能,让我们的代码更上一层楼!
算法策略:两步法
为了解决这个问题,我们将采用一种两步法:
- 遍历链表: 使用两个指针,
curr
和prev
,遍历链表。 - 检查重复: 如果
curr
节点与prev
节点相等,则删除curr
节点。
代码实现:
func deleteDuplicates(_ head: ListNode?) -> ListNode? {
var curr = head
var prev: ListNode? = nil
while curr != nil {
if prev == nil || prev!.val != curr!.val {
prev = curr
} else {
prev?.next = curr?.next
}
curr = curr?.next
}
return head
}
算法解析
我们的代码从头结点开始遍历链表。两个指针,curr
和 prev
,一路同行。如果 curr
节点与 prev
节点相等,则说明遇到了重复元素,我们通过将 prev
的 next
指向 curr
的 next
来删除 curr
节点。否则,prev
指向 curr
,curr
移动到下一个节点。这种方法确保了链表中的每个元素都只出现一次。
性能分析
算法的时间复杂度为 O(n),其中 n 是链表中的节点数。遍历链表需要 O(n) 时间。对于每个节点,我们最多进行一次恒定时间操作,因此总的复杂度为 O(n)。
实例示例
让我们用一个示例链表 [1, 1, 2, 3, 3] 来演示算法。
- 遍历链表时,
curr
指向第一个1
节点,prev
为nil
。 - 由于
prev
为nil
,所以我们保留curr
节点。 - 现在,
curr
指向第二个1
节点,prev
指向第一个1
节点。 - 由于
curr
和prev
相等,我们删除curr
节点。prev
的next
直接指向第三个节点。 - 继续遍历,我们删除第二个
3
节点,最终得到一个不重复元素的链表:[1, 2, 3]。
总结
通过解决 LeetCode #83 题,我们加强了我们在链表操作和算法解决问题方面的技能。我们的两步法算法有效地删除了重复元素,同时保持了链表的顺序。无论是初学者还是经验丰富的程序员,LeetCode 都是磨练算法技巧和加深对数据结构理解的宝贵平台。让我们继续征服 LeetCode 的挑战,一步步提升我们的编程实力!
常见问题解答
-
算法是否有空间复杂度?
算法的空间复杂度为 O(1),因为我们只使用有限数量的指针和变量。 -
算法是否适用于未排序的链表?
不,算法要求链表已经排序,否则无法有效地检测重复元素。 -
如何处理链表中的循环?
算法无法处理链表中的循环,因为它可能会陷入无限循环。 -
算法是否可以在原地修改链表?
是的,算法可以在原地修改链表,无需创建新的链表。 -
如何扩展算法以删除所有元素,而不只是重复元素?
可以通过在算法的开头添加一个条件来实现,该条件检查curr
节点是否为nil
。如果是,则删除链表的所有元素。