前言
前段时间我们学习到了单链表和双向链表的相关知识,下面我们解决一道具有代表性的一个编程题。
牛客网—环形链表的约瑟夫问题
1.题目
2.解题思路
2.1创建节点
//创建节点
ListNode *LTByBode(int n)
{
ListNode *newnode= (ListNode*)malloc(sizeof (ListNode));
newnode->val=n;
newnode->next=NULL;
return newnode;
}
2.2.创建环形链表
//创建环形链表
ListNode *circleList(int x)
{
ListNode *phead= LTByBode(1);
ListNode *ptail=phead;
for(int i=2;i<=x;i++)
{
ptail->next= LTByBode(i);
ptail=ptail->next;
}
//现在到了最后一个节点,然后首尾相连
ptail->next=phead;
return ptail;
}
2.3.进行遍历
1.首先要使用cnt进行计数,每走一步记录一次,开始的时候cnt=1。
还要创建两个指针,分别指向环形链表的第一个最小值(prev)和第二个最小值(pcur=prev->next)
2.如果cnt!=m,那么两个指针都往后走,cnt+1.
3.如果cnt==m,那么,先将prev的下一个指针,指向pcur的下一个指针(prev->next=pcur->next)。然后释放掉pcur,其次pcur也要往后移动(pcur=pcur->next),cnt恢复到默认值(cnt=1)。
4.循环的停止条件是pcur的下一个指针指向了自己(pcur->next=pcur)。
int ysm(int n,int m)
{
ListNode *prev= circleList(n);
ListNode *pcur=prev->next;
int cnt=1;
while (pcur->next!=pcur)
{
if(cnt==m){
prev->next=pcur->next;
free(pcur);
pcur=prev->next;
cnt=1;
}else {
prev=pcur;
pcur=pcur->next;
cnt++;
}
}
return pcur->val;
}
4参考代码
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param n int整型
* @param m int整型
* @return int整型
*/
#include <stdlib.h>
typedef struct ListNode Listnode ;
//创建节点
Listnode* SLTByNode(int x)
{
Listnode* tmp=(Listnode*)malloc(sizeof(Listnode));
tmp->next=NULL;
tmp->val=x;
return tmp;
}
//创建循环链表
Listnode* CreateCircle(int x)
{
//先创建第一个字节
Listnode*phead=SLTByNode(1);
Listnode*ptail=phead;
for(int i=2;i<=x;i++)
{
ptail->next=SLTByNode(i);
ptail=ptail->next;
}
//首尾相连,形成循环
ptail->next=phead;
return ptail;
}
int ysf(int n, int m ) {
// write code here
Listnode* prev=CreateCircle(n);
Listnode*pcur=prev->next;
int cnt=1;
while(pcur->next!=pcur)
{
if(cnt==m)
{
//销毁pcur
prev->next=pcur->next;
free(pcur);
pcur=prev->next;
cnt=1;
}else {
//不需要销毁
prev=pcur;
pcur=pcur->next;
cnt++;
}
}
return pcur->val;
}
完