// 两个链表的第一个交点
// 遍历对比方法时间复杂度为O(mn)
// 分析,两个链表有交点,则交点后合并为一个链表,因此可以遍历时把两个链表节点放在两个栈中
// 弹出对比直到最后一个相同点即为第一个公共交点,该方法时间复杂度O(m+n),空间复杂度O(m+n)
// 另一种更好的方法,通过获取两个链表的长度,用两个指针,在较长的指针上先走n-m步长,然后两
// 个指针同时遍历向后比较,找到第一个公共节点
typedef struct list_node
{
int value;
LIST_NODE* next;
} LIST_NODE;
LIST_NODE* find_common_node(LIST_NODE* head1, LIST_NODE* head2)
{
if (head1 == nullptr || head2 == nullptr)
{
return nullptr;
}
LIST_NODE* list1 = head1;
LIST_NODE* list2 = head2;
int list_len1 = 0;
int list_len2 = 0;
while (list1 != nullptr)
{
list_len1++;
list1 = list1->next;
}
while (list2 != nullptr)
{
list_len2++;
list2 = list2->next;
}
LIST_NODE* long_list = nullptr;
LIST_NODE* short_list = nullptr;
int long_len = 0;
int short_len = 0;
if (list_len1 >= list_len2)
{
long_list = head1;
short_list = head2;
long_len = list_len1;
short_len = list_len2;
}
else
{
long_list = head2;
short_list = head1;
long_len = list_len2;
short_len = list_len1;
}
while (long_len > short_len)
{
long_list--;
long_list = long_list->next;
}
while (long_list != nullptr && short_list != nullptr)
{
if (long_list == short_list)
{
return long_list;
}
long_list = long_list->next;
short_list = short_list->next;
}
return nullptr;
}
// 查找单链表中的环,环的长度,以及环的起始位置
// 思路:
// 两个指针,一个快指针,一个慢指针,同时从链表头开始,如果能追上则表示链表有环
// 确定环的大小可以在两个指针第一次相遇后计数,直到第二次相遇
// 确定入口位置:
// 假设慢指针到达入口位置,快指针距离入口距离为x,另外设入口位置距离起始距离为a
// 环的周长为r,则可以得到2a=a+x+nr => a=x+nr
// 那么快指针想追上满指针需要多走r-x,也即满指针也需要走r-x步,即相遇点在x的对称点
// 那么因此,在第一次相遇后,在从链表头开始一个慢指针,则两个慢指针相遇点即为入口位置
// 返回值,-1表示没有环,大于0的值表示环的大小
int find_list_circle(LIST_NODE* head)
{
if (head == nullptr)
{
return -1;
}
int circle_len = 0;
int count = 0;
LIST_NODE* fast_point = head;
LIST_NODE* slow_point = head;
while (slow_point->next != nullptr && fast_point->next != nullptr && fast_point->next->next != nullptr)
{
slow_point = slow_point->next;
fast_point = fast_point->next->next;
// 相遇
if (slow_point == fast_point)
{
if (count == 1)
{
return circle_len + 1;
}
count++;
continue;
}
if (count > 0)
{
circle_len++;
}
}
return -1;
}
// 先确定有环,然后确定入口
LIST_NODE* find_entry_node(LIST_NODE* head)
{
if (head == nullptr)
{
return nullptr;
}
LIST_NODE* fast_point = head;
LIST_NODE* slow_point = head;
LIST_NODE* slow_point_entry = head;
int meet_flag = 0;
while (slow_point->next != nullptr && fast_point->next != nullptr && fast_point->next->next != nullptr
&& slow_point_entry->next != nullptr)
{
if (!meet_flag)
{
slow_point = slow_point->next;
fast_point = fast_point->next->next;
if (slow_point == fast_point)
{
meet_flag = 1;
}
}
else
{
slow_point = slow_point->next;
slow_point_entry = slow_point_entry->next;
if (slow_point == slow_point_entry)
{
return slow_point;
}
}
}
return nullptr;
}
// 应用
// 确定两个链表的第一个公共节点
// 使用单链表环的思路来确定第一个公共节点
// 思路:
// 将链表2的首尾相连,然后从链表1头开始,则如果有公共节点,则第一个公共节点为环的入口
LIST_NODE* find_common_node(LIST_NODE* head1, LIST_NODE* head2)
{
if (head1 == nullptr || head2 == nullptr)
{
return nullptr;
}
LIST_NODE* list1 = head1;
LIST_NODE* list2 = head2;
while (list2->next != nullptr)
{
list2 = list2->next;
}
list2->next = head2;
LIST_NODE* common_node = find_entry_node(list1);
list2->next = nullptr;
return common_node;
}
// 先确定有环,然后确定入口,find_entry_node简化实现方式
// 注意,如果这个链表退化成一个完整的环依然成立
LIST_NODE* find_entry_node(LIST_NODE* head)
{
if (!head)
{
return nullptr;
}
LIST_NODE* fast = head;
LIST_NODE* slow = head;
LIST_NODE* slow2 = head;
while (!fast->next && !fast->next->next)
{
fast = fast->next->next;
slow = slow->next;
// 已经有环
if (fast == slow)
{
while (slow != slow2)
{
slow = slow->next;
slow2 = slow2->next;
}
return slow;
}
}
return nullptr;
}
两个单链表交点问题以及单链表环入口问题及其应用在两个单链表交点查找
最新推荐文章于 2024-07-19 22:36:19 发布