【链表经典算法OJ题】(2)

4.链表的中间节点

单链表相关经典算法OJ题4: 链表的中间结点

思路: 

问题的关键也在于我们无法直接得到单链表的长度 n,常规方法也是先遍历链表计算 n,再遍历一次得到第 n / 2 个节点,也就是中间节点。

如果想一次遍历就得到中间节点,也需要耍点小聪明,使用「快慢指针」的技巧:
我们让两个指针 slow 和 fast 分别指向链表头结点 head。
每当慢指针 slow 前进一步,快指针 fast 就前进两步,这样,当 fast 走到链表末尾时,slow 就指向了链表中点。

实现代码:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode* middleNode(struct ListNode* head) 
{
    struct ListNode*fast=head,*slow=head;
    while(fast&&fast->next)
    {
        slow=slow->next;
        fast=fast->next->next;
    }
   
    return slow;
}

5.环形链表的约瑟夫问题

循环链表经典应⽤-环形链表的约瑟夫问题环形链表的约瑟夫问题_牛客题霸_牛客网编号为 1 到 n 的 n 个人围成一圈。从编号为 1 的人开始报数,报到 m 的人离开。。题目来自【牛客题霸】icon-default.png?t=N7T8https://www.nowcoder.com/practice/41c399fdb6004b31a6cbb047c641ed8a

 思路:

  • 成环, 返还tail结点
  • 初始化前哨指针,和当前指针
  • 遍历计数,当技术等于m了,则摘掉当前结点,从下个结点开始
  • 返回最一个指针,即当前指针的val

代码实现:

/**
 * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
 *
 * 
 * @param n int整型 
 * @param m int整型 
 * @return int整型
 */
typedef struct ListNode ListNode;
//创建节点
ListNode* buyNode(int x)
{
	ListNode* node = (ListNode*)malloc(sizeof(ListNode));
	if (node == NULL)
	{
		exit(1);

	}
	node->val = x;
	node->next = NULL;
	return node;
}

//创建带环链表
ListNode*createCircle(int n) 
{
	//先创建第一个节点
	ListNode* phead = buyNode(1);
	ListNode* ptail = phead;
	for (int i = 2; i <= n; i++)
	{
		ptail->next = buyNode(i);
		ptail = ptail->next;
	}
	//首尾相连,链表成环
	ptail->next = phead;
	return ptail;
}

int ysf(int n, int m)
{
	//1.根据n创建带环链表
	ListNode* prev = createCircle(n);
	ListNode* pcur = prev->next;
	int count = 1;
	//当链表中只有一个节点的情况
	while (pcur->next!=pcur)
	{
		if (count == m)
		{
			//销毁pcur节点
			prev->next = pcur->next;
			free(pcur);
			pcur = prev->next;
			count = 1;
		}
		else
		{
			//此时不需要销毁节点
			prev = pcur;
			pcur = pcur->next;
			count++;
		}
	}
	//此时剩下的一个节点就是要返回的节点里的值
	return pcur->val;
}

6.合并两个有序链表

单链表相关经典算法OJ题6: 分割链表

思路:

创建大小链表,比x大的插入大链表,比x小的插入小链表。

代码实现: 

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */

typedef struct ListNode ListNode;
struct ListNode* partition(struct ListNode* head, int x)
{
	//创建两个带头链表
	ListNode* lessHead, * lessTail;
	ListNode* greaterHead, * greaterTail;
	lessHead = lessTail = (ListNode*)malloc(sizeof(ListNode));
	greaterHead = greaterTail = (ListNode*)malloc(sizeof(ListNode));

	//遍历原链表,将原链表的节点尾插到大小链表中
	ListNode* pcur = head;
	while(pcur)
	{
		if (pcur->val < x)
		{
			//尾插到小链表中
			lessTail->next = pcur;
			lessTail = lessTail->next;
		}
		else
		{
			//尾插到大链表中
			greaterTail->next = pcur;
			greaterTail = greaterTail->next;

		}
		pcur = pcur->next;

	}

    //修改大链表的尾节点的next指针指向
	greaterTail->next = NULL;//若不加这一行,代码会出现死循环

	//小链表的尾节点和大链表的第一个有效节点首尾相接
	lessTail->next = greaterHead->next;


	ListNode* ret = lessHead->next;

	free(lessHead);
	free(greaterHead);
	lessHead = greaterHead = NULL;

	return ret;
}

本篇文章介绍了题目的部分解法。如果本篇有补充的地方,欢迎私信我或在评论区指出,期待与你们共同进步。

  • 23
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值