[Data structure] Linked list exercises (2)


1. Intersecting linked list (LeetCode160)

Given the head nodes headA and headB of two singly linked lists, please find and return the starting node where the two singly linked lists intersect. Returns null if there is no intersecting node between the two linked lists. The title data guarantees that there are no loops in the entire chain structure. Note that the linked list must maintain its original structure after the function returns the result. OJ linkinsert image description here 思路
First, we have to determine whether the two linked lists intersect. If two linked lists intersect, the addresses of their tail nodes must be the same. There are two ways to get the first node where two linked lists intersect.
Method 1 : Suppose chain a has m nodes and chain b has n nodes. Use a pointer pa to point to the node of a, use another pointer pb to traverse the b chain, and judge whether the addresses are equal one by one. If they are equal, return the address of this node. If they are not equal, let pa point to the next node of a, let pb continue to traverse the chain, and continue to judge whether the addresses are equal. But the time complexity of this method is O(mn);
Method 2 : (1) Find the lengths of the two linked lists separately, get the length difference of the two linked lists, and judge whether they intersect by the way; (2) Take the gap step first for the long linked list; (3) Go at the same time, the first node with the same address is the intersection point. Time complexity is O(n) and space complexity is O(1).

//法2
struct ListNode 
{
	int val;
	struct ListNode* next;	
}; 
struct ListNode* getIntersectionNode(struct ListNode* headA, struct ListNode* headB)
{
	struct ListNode* tailA = headA, * tailB = headB;
	int lenA = 1, lenB = 1;//为什么是1?因为当tailA和tailB指向尾节点时,停止循环,len少算了一次
	while (tailA->next )//为什么当tailA指向尾节点时停止循环?因为我们要判断两链表是否相交,需要尾节点的地址
	{
		lenA++;
		tailA = tailA->next;
	}
	while (tailB->next )
	{
		lenB++;
		tailB = tailB->next;
	}
	if (tailA != tailB)
	{
		return NULL;
	}
	int gap = lenA - lenB;//假设A比B长
	struct ListNode* longList = headA;
	struct ListNode* shortList = headB;
	if (lenA < lenB)
	{
		gap = lenB - lenA;
		longList = headB;
		shortList = headA;
	}
	while (gap--)//长链表先走gap步
	{
		longList = longList->next;
	}
	while (longList != shortList)
	{
		longList = longList->next;
		shortList = shortList->next;
	}
	return longList;
}

2. Ring linked list (LeetCode141)

Give you the head node head of a linked list, and judge whether there is a ring in the linked list .
If there is a node in the linked list that can be reached again by continuously tracking the next pointer, then there is a cycle in the linked list. In order to represent the ring in the given linked list, the evaluation system internally uses the integer pos to indicate the position where the end of the linked list is connected to the linked list (the index starts from 0). Note: pos is not passed as a parameter. Just to identify the actual situation of the linked list.
Returns true if there is a cycle in the linked list. Otherwise, returns false. OJ links
insert image description here
思路
use fast and slow pointers, the slow pointer takes one step, and the fast pointer takes two steps. If it is a circular linked list, the two pointers will eventually meet in the ring, which means that the linked list is a circular linked list.
代码

struct ListNode 
{
	int val;
	struct ListNode* next;	
};
bool hasCycle(struct ListNode* head)
{
	struct ListNode* slow = head, * fast = head;
	while (fast && fast->next)//如果没有环,fast最先指向NULL,或者fast->next指向NULL
	{
		fast = fast->next->next;
		slow = slow->next;
		if (fast == slow)
		{
			return true;
		}
	}
	return false;
}

疑惑
(1) Why do slow take one step, fast take two steps, and finally meet? Will you miss it?
insert image description here
(2) If slow takes m steps and fast takes n steps, will they meet?
insert image description here


3. Ring Linked List Ⅱ (LeetCode142)

Given the head node head of a linked list, return the first node of the linked list starting to enter the ring. Returns null if the linked list is acyclic.
If there is a node in the linked list that can be reached again by continuously tracking the next pointer, then there is a cycle in the linked list. In order to represent the ring in the given linked list, the evaluation system internally uses the integer pos to indicate the position where the end of the linked list is connected to the linked list (the index starts from 0). If pos is -1, there are no cycles in the list. Note: pos is not passed as a parameter, it is just to identify the actual situation of the linked list.
The linked list is not allowed to be modified. OJ link
insert image description here
知识准备
insert image description here
思路
(method 1) According to the above knowledge preparation, we can first use the fast and slow pointers to find the meeting point, then let one pointer start from the starting point, and the other pointer start from the meeting point, and when they are equal, we can get the entry into the ring first node.
(Method 2) After using the fast and slow pointers to find the meeting point, disconnect the meeting point from the next node, and convert the problem into finding the first intersection point of two linked lists.
代码

//法1
struct ListNode 
{
	int val;
	struct ListNode* next;	
};
struct ListNode* detectCycle(struct ListNode* head)
{
	struct ListNode* slow = head, * fast = head;
	while (fast && fast->next)
	{
		slow = slow->next;
		fast = fast->next->next;
		if (slow == fast)
		{
			struct ListNode* meet = slow;
			struct ListNode* start = head;
			while (meet != head)
			{
				meet = meet->next;
				start = start->next;
			}
			return meet;
		}
	}
	return NULL;
}
//法2
struct ListNode
{
	int val;
	struct ListNode* next;
};
struct ListNode* getIntersectionNode(struct ListNode* headA, struct ListNode* headB)
{
	struct ListNode* tailA = headA, * tailB = headB;
	int lenA = 1, lenB = 1;//为什么是1?因为当tailA和tailB指向尾节点时,停止循环,len少算了一次
	while (tailA->next)//为什么当tailA指向尾节点时停止循环?因为我们要判断两链表是否相交,需要尾节点的地址
	{
		lenA++;
		tailA = tailA->next;
	}
	while (tailB->next)
	{
		lenB++;
		tailB = tailB->next;
	}
	if (tailA != tailB)
	{
		return NULL;
	}
	int gap = lenA - lenB;//假设A比B长
	struct ListNode* longList = headA;
	struct ListNode* shortList = headB;
	if (lenA < lenB)
	{
		gap = lenB - lenA;
		longList = headB;
		shortList = headA;
	}
	while (gap--)//长链表先走gap步
	{
		longList = longList->next;
	}
	while (longList != shortList)
	{
		longList = longList->next;
		shortList = shortList->next;
	}
	return longList;
}
struct ListNode* detectCycle(struct ListNode* head)
{
	struct ListNode* slow = head, * fast = head;
	while (fast && fast->next)
	{
		slow = slow->next;
		fast = fast->next->next;
		if (slow == fast)
		{
			struct ListNode* meet = slow;
			struct ListNode* list1 = meet->next;
			struct ListNode* list2 = head;
			meet->next = NULL;
			return getIntersectionNode(list1, list2);
		}
	}
	return NULL;
}

Guess you like

Origin blog.csdn.net/Zhuang_N/article/details/129386131