[Data structure] Linked list exercises (1)


1. Remove linked list elements (LeetCode203)

Given you a linked list head node head and an integer val, please delete all nodes satisfying Node.val == val in the linked list, and return a new head node. OJ link

insert image description here
思路
Create a new linked list, and insert the tail of the node not equal to val into the new linked list.

代码

struct ListNode 
{
	int val;
	struct ListNode* next;	
};
struct ListNode* removeElements(struct ListNode* head, int val)
{
	struct ListNode* NewHead = NULL;//创建一个新的头结点
	struct ListNode* cur = head;//用来遍历整个链表
	struct ListNode* tail = NULL;//指向新链表的最后一个结点,用来尾插数据
	while (cur)
	{
		if (cur->val == val)//相等就把这个结点释放
		{
			struct ListNode* tmp = cur->next;//储存下一个结点的地址,防止节点释放后找不到下一个结点
			free(cur);
			cur = tmp;
		}
		else
		{
			if (NewHead == NULL)//将头结点指向不等于val的第一个元素
			{
				NewHead = tail = cur;
			}
			else
			{
				tail->next = cur;//尾插新结点
				tail = tail->next;//指向新链表的最后一个结点
			}
			cur = cur->next;
		}
	}
	if (tail)//如果最后一个结点刚好是val,那就tail指向的下一个结点置为NULL
	{        //如果链表是空,也不会进行对NULL的访问
		tail->next = NULL;
	}
	return NewHead;
}

结果
insert image description here


2. The intermediate node of the linked list (LeetCode876)

Given the head node head of the singly linked list, please find and return the middle node of the linked list. If there are two intermediate nodes, return the second intermediate node. OJ link
insert image description here
思路
The general idea is to traverse the entire linked list, get the number of nodes in the linked list to get the subscript of the intermediate node, and then traverse the linked list to find and return this node. But I am introducing a powerful method: fast and slow pointers , the slow pointer takes one step in each cycle, and the fast pointer takes two steps in each cycle. Finally, if the length of the linked list is odd, the fast pointer points to the last node of the linked list, and the slow pointer just points to For the intermediate node, if the length of the linked list is an even number, the fast pointer points to NULL pointed to by the last node, and the slow pointer points to the second node of the two intermediate nodes.
代码

struct ListNode 
{
	int val;
	struct ListNode* next;
};
struct ListNode* middleNode(struct ListNode* head) 
{
	struct ListNode* slow = head, * fast = head;
	while (fast != NULL && fast->next != NULL)//用&&是因为只要有一个不满足就停止循环
	{
		slow = slow->next;
		fast = fast->next->next;
	}
	return slow;
}

结果
insert image description here


3. The k-th node from the bottom of the linked list (sword refers to offer)

Input a linked list and output the kth last node in the linked list. OJ links
insert image description here
思路
still use the method of fast and slow pointers. If the kth from the bottom is required, the fast pointer will take k steps first. At this time, the distance between the fast pointer and the slow pointer is k steps, and then take one step with the full pointer each time. When the fast pointer points to NULL, the distance between the slow pointer and the fast pointer The distance is k steps, the distance between the slow pointer and the last node is k-1 steps, and the slow pointer is just the last kth node.
代码

struct ListNode 
{
	int val;
	struct ListNode* next;
};
struct ListNode* FindKthToTail(struct ListNode* pListHead, int k) {
    struct ListNode* slow, * fast = NULL;
    slow = fast = pListHead;
    while (k--)//fast先走k步
    {
        if (fast == NULL)//走出链表,就直接返回NULL
        {
            return NULL;
        }
        fast = fast->next;
    }
    //此时fast与slow的距离是k,当fast指向NULL,
    //slow与最后一个节点的距离就是k-1,slow就是倒数第k个
    while (fast)
    {
        slow = slow->next;
        fast = fast->next;
    }
    return slow;
}

结果
insert image description here


4. Reverse Linked List (LeetCode206)

Given the head node head of the singly linked list, please reverse the linked list and return the reversed linked list. OJ link
insert image description here
思路
method 1 uses three pointers (n1, n2, n3) to achieve reverse order, n2 points to the current node, n3 points to the next node, and n1 points to the previous node. As shown in the picture.
insert image description here

Method 2 creates a new linked list, takes out the node head of the reversed linked list and inserts it into the new linked list.
insert image description here
代码

//法1
struct ListNode 
{
    int val;
    struct ListNode* next;
    
};
struct ListNode* reverseList(struct ListNode* head)
{
    if (head == NULL)//检查是否为空
    {
        return NULL;
    }
    struct ListNode* n1 = NULL,*n2 =head,*n3 =head->next;
    while (n2)//一旦n2指向NULL就停止循环
    {
        n2->next = n1;
        n1 = n2;
        n2 = n3;
        if (n3)//防止n3越界访问,一旦n3指向NULL,就不再改变
        {
            n3 = n3->next;
        }
    }
    return n1;
}
//法2
struct ListNode 
{
    int val;
    struct ListNode* next;
    
};
struct ListNode* reverseList(struct ListNode* head)
{
    struct ListNode* newHead = NULL;
    struct ListNode* cur = head;//遍历链表
    while (cur)
    {
        struct ListNode* next = cur->next;//记住下一个结点
        cur->next = newHead;//指向头结点指向的结点
        newHead = cur;
        cur = next;
    }
    return newHead;//不用检查链表为空,因为为空不进入循环,返回NULL
}

结果
insert image description here


5. Merge two ordered linked lists (LeetCode21)

Merges two ascending lists into a new ascending list and returns. The new linked list is formed by splicing all the nodes of the given two linked lists. OJ Linkinsert image description here
思路
Create a new linked list to compare the nodes of two ascending linked lists, and insert the smaller node. As shown in the picture.insert image description here
代码

struct ListNode 
{
	int val;
	struct ListNode* next;
	
};
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2)
{
	struct ListNode* cur1 = list1, * cur2 = list2;//分别遍历两个链表
	struct ListNode* head = NULL,*tail = head;//head是新链表的头结点,tail指向新链表的最后一个结点,方便尾插
	if (list1 == NULL)//如果有链表为空,返回另一个链表
	{
		return list2;
	}
	if (list2 == NULL)
	{
		return list1;
	}
	while (cur1 && cur2)//有一个是NULL就结束循环
	{
		if (cur1->val < cur2->val)
		{
			if (head == NULL)//考虑到第一次插入节点
			{
				head = tail = cur1;
			}
			else
			{
				tail->next = cur1;
				tail = tail->next;
				cur1 = cur1->next;//cur1还指向原来链表的下一个结点,所以不用用指针记录下一个结点
			}
		}
		else
		{
			if (head == NULL)//考虑到第一次插入节点
			{
				head = tail = cur2;
			}
			else
			{
				tail->next = cur2;
				tail = tail->next;
				cur2 = cur2->next;//cur1还指向原来链表的下一个结点,所以不用用指针记录下一个结点
			}
		}
	}
	if (cur1 == NULL)//说明list2还有结点,直接插到新链表的尾部即可
	{
		tail->next = cur2;
	}
	if (cur2 == NULL)
	{
		tail->next = cur1;
	}
	return head;
}

结果
insert image description here


6. Linked list segmentation (Niu Ke)

There is a head pointer ListNode*pHead of a linked list, given a certain value x, write a piece of code to arrange all nodes smaller than x before the rest of the nodes, and the original data order cannot be changed, and return the head pointer of the rearranged linked list. OJ link
思路
Insert the nodes less than x into a linked list, insert the nodes greater than or equal to x into another linked list, and then link the two linked lists.
预备知识
When using a singly linked list, we usually use a pointer to point to the first node as the head node, and this question needs to use the head node of the sentinel bit, and use a node to point to the first node of the linked list . What is a sentinel head node? As the name implies, it is a node. This node does not store data and only points to the first node. As for its function, it will be mentioned later. Now you only need to know that it is a node that does not store data and points to the first node. point .
insert image description here

代码

struct ListNode {
    int val;
    struct ListNode* next;
};
struct ListNode* partition(struct ListNode* pHead, int x)
{
    struct ListNode* smallGuard = (struct ListNode*)malloc(sizeof(struct ListNode));
    struct ListNode* bigGuard = (struct ListNode*)malloc(sizeof(struct ListNode));
    smallGuard->next = NULL;
    bigGuard->next = NULL;
    struct ListNode* smallTail = smallGuard, * bigTail = bigGuard, * cur = pHead;
    while (cur)
    {
        if (cur->val < x)
        {
            smallTail->next = cur;
            smallTail = smallTail->next;
        }
        else
        {
            bigTail->next = cur;
            bigTail = bigTail->next;
        }
        cur = cur->next;
    }
    smallTail->next = bigGuard->next;//将大链表链接到另一个链表,
    bigTail->next = NULL;//同时记得将大链表的最后一个节点指向NULL,防止其指向链表的另一个节点,导致环形链表
    pHead = bigGuard->next;//将新链表的头节点赋值给phead,因为哨兵位的头节点要释放
    free(bigGuard);
    free(smallGuard);
    bigGuard = NULL;
    smallGuard = NULL;
    return pHead;
}

结果
insert image description here

哨兵位头节点的作用
insert image description here


7. Palindrome structure of linked list (Niu Ke)

For a linked list, please design an algorithm with a time complexity of O(n) and an additional space complexity of O(1) to determine whether it is a palindrome. Given the head pointer A of a linked list, please return a bool value representing whether it is a palindrome. Ensure that the length of the linked list is less than or equal to 900.
insert image description here
思路
First find the middle node (you can use the previous function), start from the middle node, reverse the order of the second half (use the previous function), and finally judge whether the first half and the second half are equal.
insert image description here

代码

struct ListNode {
    int val;
    struct ListNode* next;
};
struct ListNode* middleNode(struct ListNode* head) {
    struct ListNode* slow, * fast;
    slow = fast = head;
    while ((fast != NULL) && (fast->next != NULL)) {
        slow = slow->next;
        fast = fast->next->next;
    }
    return slow;
}
struct ListNode* reverseList(struct ListNode* head) {
    struct ListNode* newHead = NULL;
    struct ListNode* cur = head;
    while (cur) {
        struct ListNode* next = cur->next;
        cur->next = newHead;
        newHead = cur;
        cur = next;
    }
    return newHead;
}
bool chkPalindrome(struct ListNode* head)
{
    struct ListNode* mid = middleNode(head);
    struct ListNode* rhead = reverseList(head);
    while (rhead && head)//当有偶数个节点时,rhead先遇到NULL,当有奇数个节点时,head和rhead同时遇到NULL
    {
        if (rhead->val != head->val)
        {
            return false;
        }
    }
    return true;
}

结果
insert image description here


Guess you like

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