A question that combines recursion, linked list, reference, and double pointer-palindrome linked list

Insert picture description hereTitle description : Given a linked list, and then you judge whether it is a palindrome linked list, it will return true if it is a palindrome linked list, otherwise it will return false; for
example, the 1 2 3 5 3 2 1sum 1 2 3 5 5 3 2 1is a palindrome linked list;
restriction conditions : control time complexity is O(n), space The complexity is O(1); the
idea of ​​solving the problem :
step1 : To determine whether it is a palindrome linked list, it is necessary to determine whether the elements in the first half (order) and the second half (reverse order) are all the same; therefore, we must first find the linked list The intermediate node ;
here may think of traversing the node once to get the length size, and then traversing the size/2 node from the beginning to get the intermediate node. This is a common method, which requires 1.5 traversal of the linked list; and it will be used ofDouble pointer-fast and slow pointerThe method only needs to traverse the linked list 0.5 times. The principle is that the fast pointer can take two steps each time and the slow pointer takes one step each time, so that when the fast pointer reaches the end point (NULL), the slow pointer just points to the second half of the linked list. The first element of Insert picture description here
method one
step2 : At this time, it is easier to think of inverting the second half of the linked list, and then compare the first half and the second half of the inverted linked list, so the second step is to reverse the linked list ; Only now、pre、aftthree nodes are required to reverse the linked list; Insert picture description here
step3 : Traverse the two linked lists in turn, and compare whether the two elements at the corresponding positions are equal;

Insert picture description here
Code :

bool isPalindrome(ListNode* head) {
    
    //O(n)、O(1)
    ListNode* slow = head, *fast = head;
    while (fast) //find mid node
    {
    
    
        slow = slow->next;
        fast = fast->next ? fast->next->next: fast->next;
    }
    ListNode *prev = nullptr;
    while (slow) //reverse
    {
    
    
        ListNode* temp = slow->next;
        slow->next = prev;
        prev = slow;
        slow = temp;
    }
    while (head && prev) //check
    {
    
    
        if (head->val != prev->val){
    
    
            return false;
        }
        head = head->next;
        prev = prev->next;
    }
    return true;
}

Method 2 :
Use a recursive method to determine whether it is a palindrome linked list;
step2 :
1° Find repetitions: find repetitive sub-problems
Insert picture description here
Here we can probably getRecursionThe general appearance of the function is:
void check(ListNode *head1,int l,ListNode *&head2,int r,flag) //判断链表[l~r]是否为回文链表
because the stack is first-in and last-out, head1 is a pointer to the head node. When the recursion reaches 5, it will slowly return to the recursion, walking
from the middle to the front ; and for walking from the middle to the back Pointer, we need to useQuote&head2Let's increase its value step by step and let it go backward, so as to ensure that head1 and head2 are the corresponding positions of comparison;

2° Find the change: the amount of change isl,r,head2,flag l,r代表check函数比较链表第i和第r个的元素,flag用于标志是否为回文链表,初始为true,如果出现两比较值不相等,则置为false

3° Find the boundary: We reduce the problem step by step. At the end l>=r, it means that the sub-problem has reached the minimum scale (l==r means pointing to a single element without comparison; l>r means exceeding the limit), at this time return;

Then the entire recursive function has the following form:

void check(ListNode *head1, int l, ListNode *&head2, int r, bool &flag) //判断链表[l~r]是否为回文  (注意head2是变化的 它要一次次往后走 一定要引用)
{
    
    
	//边界条件
	if (l >= r)
	{
    
    
		return;
	}
	//将问题规模缩小
	if (r - l >= 2)
	{
    
    
		check(head1->next, l + 1, head2, r - 1, flag);
	}
	//比较对应位置节点值
	int a = head1->val, b = head2->val;
	if (a != b)
	{
    
    
		flag = false;
	}
	//head2指向下一个结点,此时该函数完成返回其调用函数时,head1也指向前一个结点,这样又能比较两个数是否相等了
	head2 = head2->next;
}

step3 : Return the judgment flag flag;
Insert picture description here

void check(ListNode *head1, int l, ListNode *&head2, int r, bool &flag) //判断链表[l~r]是否为回文  (注意head2是变化的 它要一次次往后走 一定要引用)
{
    
    
	//边界条件
	if (l >= r)
	{
    
    
		return;
	}
	//将问题规模缩小
	if (r - l >= 2)
	{
    
    
		check(head1->next, l + 1, head2, r - 1, flag);
	}
	//比较对应位置节点值
	int a = head1->val, b = head2->val;
	if (a != b)
	{
    
    
		flag = false;
	}
	//head2指向下一个结点,此时该函数完成返回其调用函数时,head1也指向前一个结点,这样又能比较两个数是否相等了
	head2 = head2->next;
}

bool isPalindrome(ListNode *head)
{
    
    
	//如果有1个及以下的元素,返回true
	if (head == nullptr || head->next == nullptr)
	{
    
    
		return true;
	}

	//利用快慢指针求链表个数和中间节点
	int size = 0;
	ListNode *slow = head, *fast = head, *mid_point = nullptr;
	while (fast)
	{
    
     //find mid node
		size++;
		slow = slow->next;
		fast = fast->next ? fast->next->next : fast->next;
	}
	//设置指向中间节点的指针
	mid_point = slow;
	while (slow)
	{
    
    
		size++;
		slow = slow->next;
	}
	bool flag = true;
	check(head, 1, mid_point, size, flag);
	return flag;
}

Guess you like

Origin blog.csdn.net/wyll19980812/article/details/109095237