求两个链表的交点问题也是面试算法常常考到的点,这里提供两种方法实现。
问题描述:给定两个单链表的头指针ha和hb,若两个链表存在交点,就返回该交点的指针地址,若不存在交点,则返回NULL。
这里先定义一下单链表数据结构
struct ListNode
{
int val;
ListNode *next;
ListNode(int x): val(x), next(NULL) {}
};
方法一:
使用stl的集合对象set,遍历ha链表的所有节点,将所有节点的地址加入set中;然后遍历hb链表,查看hb中的每个节点地址是否存在于set中,若存在,直接返回对应节点。遍历结束时仍未找到,返回NULL。该方法空间复杂度O(n),实现如下:
// 方法1
ListNode* get_intersection(ListNode* ha, ListNode* hb) {
std::set<ListNode*> node_set;
while (ha) {
node_set.insert(ha);
ha = ha->next;
}
while (hb) {
if (node_set.find(hb) != node_set.end()) {
return hb
}
}
return NULL;
}
方法二:
直接使用指针移动实现,可达到空间复杂度O(1),即先计算两个链表长度,将较长的那个链表的头指针移动至与较短的链表同长度的位置,再同时遍历两个链表的节点,找到它们的交点。实现如下:
int get_list_length(ListNode* head) {
int len = 0;
while (head) {
len++;
head = head->next;
}
return len;
}
ListNode* forward_list(ListNode* head, int l) {
while (head && l--) {
head = head->next;
}
return head;
}
ListNode* get_intersection(ListNode* ha, ListNode* hb) {
int len_a = get_list_length(ha);
int len_b = get_list_length(hb);
if (len_a < len_b) {
hb = forward_list(hb, len_b-len_a);
} else {
ha = forward_list(ha, len_a-len_b);
}
while (ha && hb) {
if (ha == hb) {
return ha;
}
ha = ha->next;
hb = hb->next;
}
return NULL;
}