数据结构: 两个单链表相交的一系列问题

数据结构: 两个单链表相交的一系列问题

这个是一个比较综合的问题:

  • 若两个单链表一个为有环,一个无环. 那么肯定不能相交.

  • 若二者都没有环, 问题就转化为 两个无环单链表是否相交,方法就是 快慢指针 ,是否能找到第一个相交的节点.

  • 若二者都有环,那么问题变成了两个有换单链表是否相交.

    第一,先找到二者是否相交.

    第二,若相交则需要遍历一遍找到相交点.

该题可以分解为三个问题:

1 判断一个链表是否有环

#include "MyInclude.h"

/*
	问题一:
	判断一个链表是否有环.
	如果有,返回第一个进入环的节点.
	如果没有,返回NULL
*/

// 快慢指针,若存在环,则一定会在环中的某一个节点相遇.
// 然后再找第入口
// https://blog.csdn.net/l294265421/article/details/50478818

ListNode* getLoopNode(ListNode* head) {
	// 至少有三个节点
	if (head == NULL||head->next==NULL||head->next->next==NULL) {
		return NULL;
	}

	// 初始值,slow走了一步,fast走了两步
	ListNode* slow = head->next;
	ListNode* fast = head->next->next;

	while (slow != fast) {
		// 若走到了NULL,则无环
		if (fast->next == NULL || fast->next->next == NULL) {
			return NULL;
		}
		slow = slow->next;
		fast = fast->next->next;
	}
	// 存在环,找环的第一个节点.
	slow = head;
	while (slow != fast) {
		slow = slow->next;
		fast = fast->next;
	}
	return slow;
}

2 如何判断两个无环链表相交?

/*
	若两个无环链表相交,返回相交节点,
	否则,返回NULL
*/


int getLen(ListNode* head) {
	int len = 0;
	while (head != NULL) {
		len++;
		head = head->next;
	}
	return len;
}

ListNode* noLoop(ListNode* head1, ListNode* head2) {
	if (head1 == NULL || head2 == NULL)
		return NULL;

	ListNode* p1 = head1;
	ListNode* p2 = head2;

	// 统计长度
	int len1 = getLen(p1);
	int len2 = getLen(p2);

	// 假设p1是长度比较长的
	if (len1 < len2) {
		ListNode* tmp = p1;
		p1 = p2;
		p2 = tmp;
	}

	int absDiff = (len1 - len2);

	while (absDiff != 0) {
		p1 = p1->next;
		absDiff--;
	}

	while (p1 != NULL&&p2 != NULL&&p1 != p2) {
		p1 = p1->next;
		p2 = p2->next;
	}

	if (p1 == NULL || p2 == NULL) {
		return NULL;
	}
	else {
		return p1;
	}
}

3 如何判断两个有环链表是否相交?

/*
	判断两个有环链表是否相交
	若相交,返回第一个相交点
	若不相交,返回NULL
*/


// 求出有环链表的环入口节点
ListNode* getLoopEnter(ListNode* head) {
	ListNode* slow = head->next;
	ListNode* fast = head->next->next;

	while (slow != fast) {
		slow = slow->next;
		fast = fast->next;
	}
	slow = head;
	while (slow != fast) {
		slow = slow->next;
		fast = fast->next;
	}
	return slow;
}

ListNode* BothLoop(ListNode* head1, ListNode* head2) {
	// 1.先获得两个链表各自的环的入口
	ListNode* loop1 = getLoopEnter(head1);
	ListNode* loop2 = getLoopEnter(head2);
	// 2.或在入口处相等,那么返回
	if (loop1 == loop2) {
		return loop1;
	}
	// 不相等,则遍历一遍一个环自身,看是否能找到另一个环的入口节点,有则为相交,没有则为不相交
	ListNode* p = loop1->next;
	while (p != loop1) {
		if (p == loop2) {
			return p;
		}
		p = p->next;
	}
	return NULL;
}

原题解答:

/*
	检测两个单链表是否相交,
	若相交,返回第一个相交的节点
	若不相交,返回NULL
*/

/*
	分析:
		若一个链表有环,一个链表没有换,则不可能相交

		若两个单链表都有环,
		则需要检测两个有环链表是否相交

		若二者都没有,
		则判断两个无环的单链表是否相交
*/


// 1.判断一个链表是否有环
ListNode* hasLoop(ListNode* head) {

	if (head == NULL || head->next == NULL || head->next == NULL)
		return NULL;

	ListNode* slow = head->next;
	ListNode* fast = head->next->next;

	while (slow != fast) {
		// 走到NULL,说明没有环
		if (fast->next == NULL || fast->next->next == NULL) {
			return NULL;
		}
		slow = slow->next;
		fast = fast->next->next;
	}
	slow = head;
	while (slow != fast) {
		slow = slow->next;
		fast = fast->next;
	}
	return slow;
}

// 2.两个无环链表是否相交
int getLen(ListNode* head) {
	int len = 0;
	while (head != NULL) {
		len++;
		head = head->next;
	}
	return len;
}

ListNode* noLoop(ListNode* head1, ListNode* head2) {
	if (head1 == NULL || head2 == NULL)
		return NULL;

	ListNode* p1 = head1;
	ListNode* p2 = head2;

	// 统计长度
	int len1 = getLen(p1);
	int len2 = getLen(p2);

	// 假设p1是长度比较长的
	if (len1 < len2) {
		ListNode* tmp = p1;
		p1 = p2;
		p2 = tmp;
	}

	int absDiff = (len1 - len2);

	while (absDiff != 0) {
		p1 = p1->next;
		absDiff--;
	}

	while (p1 != NULL&&p2 != NULL&&p1 != p2) {
		p1 = p1->next;
		p2 = p2->next;
	}

	if (p1 == NULL || p2 == NULL) {
		return NULL;
	} else {
		return p1;
	}
}


// 3.两个有环链表是否相交,
ListNode* bothLoop(ListNode* Loop1, ListNode* Loop2) {
	if (Loop1 == Loop2) {
		return Loop1;
	}
	else {
		ListNode* p = Loop1->next;
		while (p != Loop1) {
			if (p == Loop2)
				return p;
			p = p->next;
		}
		return NULL;
	}
}

ListNode* getInterSectNode(ListNode* head1, ListNode* head2) {

	// 1. 判断一个链表是否有环
	ListNode* Loop1 = hasLoop(head1);
	ListNode* Loop2 = hasLoop(head2);

	// 2. 若二者都是空,
	if (Loop1 == NULL&&Loop2 == NULL) {
		return noLoop(head1, head2);
	}
	if (Loop1 != NULL&&Loop2 != NULL) {
		return bothLoop(Loop1, Loop2);
	}
	return NULL;
}

猜你喜欢

转载自blog.csdn.net/qjh5606/article/details/85558148