C语言进阶|链表经典OJ题

✈移除链表元素

给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点

方法一:

遍历链表找到所有等于val的节点,再执行删除操作删除这些节点。

方法二:

双指针

创建两个指针,一个在前,一个在后。

如果前面的指针指向的元素等于val,将后面的指针连上前面指针的下一个指针,前面的指针向前走一格;

如果前面的指针指向的元素不等于val,那么两个指针都向前走一格。

再处理一些特殊情况:

cpp 复制代码
struct ListNode* removeElements(struct ListNode* head, int val) {
	ListNode * last = head;
	ListNode* tmp = head;
	if (last == NULL || (last->next == NULL && last->val == val))//如果是空链表或只有一个val的链表
	{
		return NULL;
	}
	else if (last->next == NULL)//如果只有一个节点且不等于val的链表
	{
		return head;
	}
	else
	{
		while (tmp != NULL)
		{
			if (tmp == last)
			{
				tmp = tmp->next;
			}
			if (tmp->val==val)
			{
				last->next = tmp->next;
				tmp = tmp->next;
			}
			else
			{
				last = last->next;
				tmp = tmp->next;
			}
		}
		if (head->val == val)//如果第一个节点的元素就等于val
		{
			return head->next;
		}
		last->next = NULL;
	}
	return head;
}

原题链接:

移除链表元素

✈反转链表

给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。

双指针法:

创建两个指针,一个在前,一个在后。

每次循环,将前面的指针指向的链表指向在后面的指针,后面的指针赋值成前一个,前一个往下走一格。

cpp 复制代码
struct ListNode* reverseList(struct ListNode* head) {
	if (head == NULL || head->next == NULL)//如果只有一个或者没有节点
	{
		return head;
	}
	ListNode* pre = head->next;
	head->next = NULL;
	while (pre != NULL)
	{
		ListNode* tmp = pre->next;
		pre->next = head;
		head = pre;
		pre = tmp;
	}
	return head;
}

原题链接:

反转链表

✈合并两个有序链表

双指针法:

创建三个指针,一个指向第一个链表,一个指向第二个链表,一个指向新链表的末尾。

如果第一个指针指向的元素比第二个指针小,那么就让新链表的末尾指向第一个指针,第一个指针再向后移一格,第三个指针向后移一格;

如果第二个指针指向的元素比第一个指针小,那么就让新链表的末尾指向第二个指针,第二个指针再向后移一格,第三个指针向后移一格。

cpp 复制代码
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {
	if (list1 == NULL)//先解决其中存在空链表的情况
	{
		return list2;
	}
	else if (list2 == NULL)
	{
		return list1;
	}
	else
	{
		ListNode* pre = NULL;
		ListNode* finnal = NULL;
		if (list1->val <= list2->val)//初始化pre,确定新链表的的头节点finnal
		{
			finnal = list1;
			pre = list1;
			list1 = list1->next;
		}
		else
		{
			finnal = list2;
			pre = list2;
			list2 = list2->next;
		}
		while (list1 != NULL && list2 != NULL)//取元素到新的链表中
		{
			
			if (list1->val <= list2->val)
			{
				pre->next = list1;
				pre = list1;
				list1 = list1->next;
			}
			else
			{
				pre->next = list2;
				pre = list2;
				list2 = list2->next;
			}
		}
		if (list1 == NULL)
		{
			pre->next = list2;
		}
		else
		{
			pre->next = list1;
		}
		return finnal;
	}
}

原题链接:

合并两个有序链表

✈链表的中间节点

快慢指针法:

创建两个指针,一个快指针,一个慢指针,两个指针初始值为链表的起点。快指针每次走两格,慢指针每次走一格。

如果链表中有奇数个节点,当快指针的下一个节点为NULL时,慢指针走到中间节点的位置;

如果链表中有偶数个节点,当快指针为NULL时,慢指针走到中间节点的位置。

cpp 复制代码
typedef struct ListNode ListNode;
struct ListNode* middleNode(struct ListNode* head) {
	ListNode* fast = head;
	ListNode* slow = head;
	while (1)
	{
		if (fast == NULL || fast->next == NULL)
		{
			return slow;
		}
		fast = fast->next;
		fast = fast->next;
		slow = slow->next;
	}

}

原题链接:

链表的中间节点

✈环形链表的约瑟夫问题

环形链表法:

创建一个n个节点的环形链表,并且第n个节点的存储的元素是n。

删去第m个的值,并且循环n-1次。

cpp 复制代码
typedef struct ListNode {
	int val;
	struct ListNode* next;
}ListNode;

int ysf(int n, int m) {
	ListNode* head = (ListNode*)malloc(sizeof(ListNode));
	assert(head);
	head->val = 1;
	head->next = head;
	ListNode* pre = head;
	for (int i = 2; i <=n; i++)
	{
		ListNode* newnode = (ListNode*)malloc(sizeof(ListNode));
		newnode->next = head;
		newnode->val = i;
		pre->next = newnode;
		pre = newnode;
	}
	for (int i = 0; i < n - 1; i++)
	{
		for (int j = 0; j < m-1; j++)
		{
			pre = pre->next;
		}
		pre->next = pre->next->next;
	}
	return pre->val;
}

原题链接:

环形链表的约瑟夫问题

相关推荐
寻星探路15 小时前
【算法专题】哈希表:从“两数之和”到“最长连续序列”的深度解析
java·数据结构·人工智能·python·算法·ai·散列表
!停15 小时前
C语言单链表
c语言·数据结构·算法
南行*15 小时前
C语言Linux环境编程
linux·c语言·开发语言·网络安全
闻缺陷则喜何志丹16 小时前
【回文 字符串】3677 统计二进制回文数字的数目|2223
c++·算法·字符串·力扣·回文
你怎么知道我是队长16 小时前
C语言---printf函数使用详细说明
c语言·开发语言
Tisfy16 小时前
LeetCode 0085.最大矩形:单调栈
算法·leetcode·题解·单调栈
消失的旧时光-194316 小时前
函数指针 + 结构体 = C 语言的“对象模型”?——从 C 到 C++ / Java 的本质统一
linux·c语言·开发语言·c++·c
mit6.82416 小时前
出入度|bfs|状压dp
算法
hweiyu0016 小时前
强连通分量算法:Kosaraju算法
算法·深度优先
源代码•宸16 小时前
Golang语法进阶(定时器)
开发语言·经验分享·后端·算法·golang·timer·ticker