文章目录
摘要
本篇文章将分享如何通过 Swift 编写程序,找到两个单链表相交的起始节点。我们将分析问题,提供清晰的题解代码,并通过示例测试验证结果。同时,文章会详细剖析代码逻辑,评估其时间复杂度和空间复杂度,助力开发者掌握高效算法的实现技巧。
描述
编写一个程序,找到两个单链表相交的起始节点。
如下面的两个链表:
在节点 c1 开始相交。
示例 1:
**输入:**intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3
**输出:**Reference of the node with value = 8
**输入解释:**相交节点的值为 8 (注意,如果两个列表相交则不能为 0)。从各自的表头开始算起,链表 A 为 [4,1,8,4,5],链表 B 为 [5,0,1,8,4,5]。在 A 中,相交节点前有 2 个节点;在 B 中,相交节点前有 3 个节点。
示例 2:
**输入:**intersectVal = 2, listA = [0,9,1,2,4], listB = [3,2,4], skipA = 3, skipB = 1
**输出:**Reference of the node with value = 2
**输入解释:**相交节点的值为 2 (注意,如果两个列表相交则不能为 0)。从各自的表头开始算起,链表 A 为 [0,9,1,2,4],链表 B 为 [3,2,4]。在 A 中,相交节点前有 3 个节点;在 B 中,相交节点前有 1 个节点。
示例 3:
**输入:**intersectVal = 0, listA = [2,6,4], listB = [1,5], skipA = 3, skipB = 2
**输出:**null
**输入解释:**从各自的表头开始算起,链表 A 为 [2,6,4],链表 B 为 [1,5]。由于这两个链表不相交,所以 intersectVal 必须为 0,而 skipA 和 skipB 可以是任意值。
**解释:**这两个链表不相交,因此返回 null。
注意:
- 如果两个链表没有交点,返回
null
. - 在返回结果后,两个链表仍须保持原有的结构。
- 可假定整个链表结构中没有循环。
- 程序尽量满足 O(n) 时间复杂度,且仅用 O(1) 内存。
题解答案
以下为 Swift 的题解实现:
class ListNode {
var val: Int
var next: ListNode?
init(_ val: Int) {
self.val = val
self.next = nil
}
}
class Solution {
func getIntersectionNode(_ headA: ListNode?, _ headB: ListNode?) -> ListNode? {
guard headA != nil && headB != nil else { return nil }
var pointerA = headA
var pointerB = headB
while pointerA !== pointerB {
pointerA = pointerA == nil ? headB : pointerA?.next
pointerB = pointerB == nil ? headA : pointerB?.next
}
return pointerA
}
}
题解代码分析
-
基本思路
使用双指针法解决问题:- 两个指针分别从
headA
和headB
开始,依次遍历链表。 - 如果指针到达链表尾部,则切换到另一个链表的头部继续遍历。
- 当两个指针相遇时,即为链表的相交节点;若无相交节点,则最终返回
nil
。
- 两个指针分别从
-
关键逻辑
- 双指针在遍历链表时,总会同时进入交点或结束(无交点时均为
nil
)。 - 通过两次遍历,确保指针在长度不同的链表上补齐长度差异。
- 双指针在遍历链表时,总会同时进入交点或结束(无交点时均为
-
核心代码解析
pointerA = pointerA == nil ? headB : pointerA?.next
当pointerA
到达链表 A 的末尾时,切换到链表 B 的头部,反之亦然。
示例测试及结果
// 示例链表创建
let common = ListNode(8)
common.next = ListNode(4)
common.next?.next = ListNode(5)
let listA = ListNode(4)
listA.next = ListNode(1)
listA.next?.next = common
let listB = ListNode(5)
listB.next = ListNode(0)
listB.next?.next = ListNode(1)
listB.next?.next?.next = common
// 测试用例
let solution = Solution()
if let intersection = solution.getIntersectionNode(listA, listB) {
print("Intersection Node Value: \(intersection.val)") // 输出:8
} else {
print("No Intersection")
}
输出结果:
Intersection Node Value: 8
时间复杂度
- 分析:
每个指针最多遍历两个链表的总长度,时间复杂度为 (O(m + n)),其中 (m) 和 (n) 分别为链表 A 和链表 B 的长度。
空间复杂度
- 分析:
仅使用了两个指针,额外空间复杂度为 (O(1))。
总结
通过双指针法,成功实现了寻找链表相交节点的高效算法。其优势在于时间复杂度 (O(n))、空间复杂度 (O(1)) 的表现。实际应用中,该方法具有较高的通用性,非常适合处理单链表相关问题。
未来可以进一步扩展到其他链表问题,例如检测链表环、合并链表等。希望本篇文章能帮助大家更好地理解和掌握链表算法的核心技巧!
标签:单链,ListNode,复杂度,相交,next,链表,Swift,节点 From: https://blog.csdn.net/qq_36478920/article/details/144461065