链表经典算法实战:相交节点查找与回文结构判断
在算法学习中,链表因其灵活的结构成为高频考点。本期将攻克两大经典问题:「相交链表」与「链表的回文结构」。通过拆解问题,提升链表类问题的实战能力。
一、相交链表
题目描述: 给你两个单链表的头节点 headA 和 headB,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null。 图示两个链表在节点 c1 开始相交: (图示:链表 A 和 B 在某一点汇合,后续节点共用)
题目数据保证整个链式结构中不存在环。注意,函数返回结果后,链表必须保持其原始结构。
1.1 思路解答 + 作图演示
- 算法思路: 由于是单链表,节点只保存着下一个节点的地址,初步可以确定为遍历两个链表。那么该如何对这两个链表进行遍历呢?
-
简单的分别遍历比较 next 指针。(废弃) 经过分析发现,如果两个链表的长度不相同,简单的分别遍历会导致在相交节点处步调错开,直到遍历完都没有找到交点。
-
先让较长的链表走完两个链表长度的差值。(最优解) 以较长的链表为基准,将较短的链表依次对比,寻找相同的节点。 这个方法虽然可行,但显然需要嵌套循环,时间复杂度为 O(N^2)。
为了消除链表长度不同导致的遍历步调不一致,可以让长链表先走,使两个链表同起点。经过推导,让长链表先走差值步数,之后二者的遍历步调一致,最终在交点相遇。时间复杂度优化至 O(N)。
1.2 验证算法
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
typedef struct ListNode ListNode;
struct ListNode* getIntersectionNode(struct ListNode* headA, struct ListNode* headB) {
// 求出两个链表的长度
// 创建临时变量,不改变链表结构
ListNode* pa = headA;
ListNode* pb = headB;
int sizeA = 0, sizeB = 0;
// 循环求长度
while (pa) {
sizeA++;
pa = pa->next;
}
while (pb) {
sizeB++;
pb = pb->next;
}
// 长度差值,使用绝对值
int gap = abs(sizeA - sizeB);
// 判断链表的长短
ListNode* longlist = headA;
ListNode* shortlist = headB;
if (sizeA < sizeB) {
longlist = headB;
shortlist = headA;
}
(gap--) {
longlist = longlist->next;
}
(longlist) {
(longlist == shortlist) {
longlist;
}
longlist = longlist->next;
shortlist = shortlist->next;
}
;
}


