题目
(题能说的言简意赅一点吗?废话那么多。)
每年六一儿童节,牛客都会准备一些小礼物去看望孤儿院的小朋友,今年亦是如此。HF作为牛客的资深元老,自然也准备了一些小游戏。其中,有个游戏是这样的:首先,让小朋友们围成一个大圈。然后,他随机指定一个数m,让编号为0的小朋友开始报数。每次喊到m-1的那个小朋友要出列唱首歌,然后可以在礼品箱中任意的挑选礼物,并且不再回到圈中,从他的下一个小朋友开始,继续0…m-1报数…这样下去…直到剩下最后一个小朋友,可以不用表演,并且拿到牛客名贵的“名侦探柯南”典藏版(名额有限哦!!_)。请你试着想下,哪个小朋友会得到这份礼品呢?(注:小朋友的编号是从0到n-1)
如果没有小朋友,请返回-1
思路
- 菜鸟能写出来的思路(我)
- 用链表构造一个环,结点代表n个小朋友。
- 计算要到被淘汰的小朋友那里需要走几步。
- 把小朋友踢走,继续循环。
- 贼屌的数学方法
- 暂时不想看,头疼。
链表代码
class Solution {
struct ListNode{
int val;
ListNode* next;
ListNode(int x) : val(x), next(nullptr){
}
};
public:
int LastRemaining_Solution(int n, int m)
{
if ( n < 1 || m < 1 ) return -1;
// 创建链表,小朋友先排队
ListNode* pBegin = new ListNode(0);
ListNode* p = pBegin;
for ( int i = 1; i < n; ++i ) {
p->next = new ListNode( i );
p = p->next;
}
// 形成环,小朋友首尾相接
p->next = pBegin;
ListNode* pre = p;
p = pBegin;
// 开始循环踢出小朋友
while ( p != p->next ) {
int tempM = m;
tempM %= n; // 如果报数大于小朋友人数,让小朋友少喊几轮
// 找到小朋友
for ( int i = 0; i < m - 1; ++i ) {
pre = p;
p = p->next;
}
// 把小朋友踢走
pre->next = p->next;
ListNode* tempNode = p;
delete tempNode;
p = pre->next;
--n; // 滚蛋一个小朋友哈哈哈哈
}
return p->val;
}
};