[Single Linked List Exercise] - Determine whether the linked list is a palindrome structure

topic description

Description
For a linked list, please design an algorithm whose time complexity is O(n) and extra space complexity is O(1), and judge whether it is a palindrome structure.
Given the head pointer A of a linked list, please return an int value representing whether it is a palindrome structure, and the length of the linked list is guaranteed to be less than or equal to 900.

Example 1

输入:1->2->2->1
输出:true

Problem solving analysis:

Idea 1: Open an array of 900, traverse the linked list to put the data into the array, record the number of elements, and judge whether the elements corresponding to the left subscript and the right subscript are equal. Judgment of the palindrome structure of the array.
Time complexity: traversal + comparison FN = N + N/2. F(N) = O(N)
Space complexity: O(1)

Idea 2: Find the middle node, reverse the second half of the same part, and then traverse the first half and the second half to compare and judge whether they are the same.
Note: Functions to find intermediate nodes. (For details, see this article " [Single Linked List Exercise] - Intermediate Node of Linked List "). Reverse the linked list (the inversion of the linked list, see this article " [Single Linked List Exercise] - Reversed Single Linked List ").
For the next of the previous node of the intermediate node, it needs to be blank, so that it is convenient to use the previous part of the loop to judge whether it is consistent with the latter part.
You can also leave it empty, and use the latter part of the cycle to judge whether it is consistent with the previous part.
insert image description here
Time complexity: inversion + finding intermediate nodes + comparing FN = N + N/2 + N/2. F(N) = O(N)
Space complexity: O(1)

Code:

struct ListNode
{
    
    
	int val;
	struct ListNode* next;
};
//链表逆置 - 反转链表
struct ListNode* reverseList(struct ListNode* head)
{
    
    
	//头插法实现链表逆置
	struct ListNode* newhead = NULL;
	struct ListNode* cur = head;
	struct ListNode* next = NULL;

	//判断空链表,或则只有一个结点的链表,这里可以不需要判断,cur为NULL,不进入循环
 	if (head == NULL || head->next == NULL)
		return head;
	//迭代
	while (cur != NULL)
	{
    
    
		next = cur->next;
		//头插
		cur->next = newhead;
		newhead = cur;
		cur = next;
	}
	return newhead;
}
int chkPalindrome(struct ListNode* A)
{
    
    
	struct ListNode* fast = A;
	struct ListNode* slow = A;
	struct ListNode* prev = NULL;//保存slow的前一个,用于断掉中间结点的联系

	//第一步:找到中间结点(偶数个节点时,中间结点为第二个结点)
	while (fast && fast->next)
	{
    
    
		prev = slow;//slow走之前,保存它的地址
		slow = slow->next;
		fast = fast->next->next;
	}
	//				     prev
	//                        slow      fast
	//奇数个结点时:1 -> 2 -> 3 -> 2 -> 1 -> NULL
	//断掉中间结点的联系,即slow前一个置为NULL
	prev->next = NULL;

	//slow是中间结点指针。
	//第二步:以slow为结点的链表逆置
	//reverseList(slow);//这里虽然逆置了,但是是值传递得到的结果没有发生变化
	//3 -> 2 -> 1		逆置后1->2->3
	slow = reverseList(slow);//需要接收它的新头结点的地址

	//第三步:分解的两个链表的比较
	while(A)//A链表为空结束,因为A链表要么比slow少一个节点,要么就相等
	{
    
    
		if (A->val != slow->val)
		{
    
    
			return 0;
		}
		else
		{
    
    
			A = A->next;
			slow = slow->next;
		}
	}
	return 1;
}

Optimization: do not disconnect links
insert image description here

Code optimization:

int chkPalindrome(struct ListNode* A)
{
    
    
	struct ListNode* fast = A;
	struct ListNode* slow = A;
	//第一步:找到中间结点
	while (fast && fast->next)
	{
    
    
		slow = slow->next;
		fast = fast->next->next;
	}

	//第二步:以slow为结点的链表逆置
	slow = reverseList(slow);

	//第三步:分解的两个链表的比较
	while(A && slow)//A或slow链表有一个为空,结束。实际上只需要判断slow为空则结束即可。
	{
    
    
		if (A->val != slow->val)
		{
    
    
			return 0;
		}
		else
		{
    
    
			A = A->next;
			slow = slow->next;
		}
	}
	return 1;
}

Guess you like

Origin blog.csdn.net/qq_48163964/article/details/130011366