题目链接:
环形链表的约瑟夫问题_牛客题霸_牛客网
题目:
描述
编号为 1 到 n 的 n 个人围成一圈。从编号为 1 的人开始报数,报到 m 的人离开。
下一个人继续从 1 开始报数。
n-1 轮结束以后,只剩下一个人,问最后留下的这个人编号是多少?
示例1
输入:
5,2
返回值:
3
说明:
开始5个人 1,2,3,4,5 ,从1开始报数,1->1,2->2编号为2的人离开 1,3,4,5,从3开始报数,3->1,4->2编号为4的人离开 1,3,5,从5开始报数,5->1,1->2编号为1的人离开 3,5,从3开始报数,3->1,5->2编号为5的人离开 最后留下人的编号是3
示例2
输入:
1,1
返回值:
1
理解分享:
-
首先检查两个输入的链表是否为空。如果其中一个为空,就返回另一个链表,因为合并后的链表就是非空链表本身。
-
定义四个指针
n1
、n2
、head
和tail
。n1
和n2
分别代表两个输入链表的当前节点,head
和tail
分别表示合并后链表的头节点和尾节点,初始时都为NULL
。 -
进入一个循环,条件是
n1
和n2
都不为空。在循环中,比较n1
和n2
当前节点的值,将值较小的节点接到合并后的链表中。如果n1
的值小于等于n2
的值,就将n1
加入合并后的链表中,反之将n2
加入。加入操作分为两种情况:如果合并后的链表为空,则将头节点和尾节点都设为当前节点;如果不为空,则将当前节点接到尾节点后,并更新尾节点为当前节点。 -
当循环结束后,可能存在其中一个链表还有剩余节点未加入合并链表中。因此,再次检查
n1
和n2
是否还有剩余节点,如果有,则将剩余节点接到合并链表的尾部。 -
最后返回合并后的链表的头节点
head
。
代码:
typedef struct ListNode ll;
//分配内存
ll* List_mem(int i)
{ll* k = (ll*)malloc(sizeof(ll));if (k == NULL){exit(1);}k->val = i;k->next = NULL;return k;
}//创建一个链表
ll* List_set(int n)
{ll* n1 = List_mem(1);ll* n2 = n1;for (int i = 2; i <= n; i++){n2->next = List_mem(i);n2 = n2->next;}n2->next = n1;return n1;
}int ysf(int n, int m) {ll* mn = List_set(n);ll* n1 = mn;ll* n2 = n1;int count = 1;//计数器while (n2->next != n1){n2 = n2->next;}while (n1->next != n1){if (count == m){n2->next = n1->next;free(n1);n1 = n2->next;count = 1;}else{n2 = n2->next;n1 = n1->next;count++;}}return n1->val;
}