共有 n 名小伙伴一起做游戏。小伙伴们围成一圈,按 顺时针顺序 从 1 到 n 编号。确切地说,从第 i 名小伙伴顺时针移动一位会到达第 (i+1) 名小伙伴的位置,其中 1 <= i < n ,从第 n 名小伙伴顺时针移动一位会回到第 1 名小伙伴的位置。
游戏遵循如下规则:
从第 1 名小伙伴所在位置 开始 。
沿着顺时针方向数 k 名小伙伴,计数时需要 包含 起始时的那位小伙伴。逐个绕圈进行计数,一些小伙伴可能会被数过不止一次。
你数到的最后一名小伙伴需要离开圈子,并视作输掉游戏。
如果圈子中仍然有不止一名小伙伴,从刚刚输掉的小伙伴的 顺时针下一位 小伙伴 开始,回到步骤 2 继续执行。
否则,圈子中最后一名小伙伴赢得游戏。
给你参与游戏的小伙伴总数 n ,和一个整数 k ,返回游戏的获胜者。
示例 1:
输入:n = 5, k = 2
输出:3
解释:游戏运行步骤如下:
1) 从小伙伴 1 开始。
2) 顺时针数 2 名小伙伴,也就是小伙伴 1 和 2 。
3) 小伙伴 2 离开圈子。下一次从小伙伴 3 开始。
4) 顺时针数 2 名小伙伴,也就是小伙伴 3 和 4 。
5) 小伙伴 4 离开圈子。下一次从小伙伴 5 开始。
6) 顺时针数 2 名小伙伴,也就是小伙伴 5 和 1 。
7) 小伙伴 1 离开圈子。下一次从小伙伴 3 开始。
8) 顺时针数 2 名小伙伴,也就是小伙伴 3 和 5 。
9) 小伙伴 5 离开圈子。只剩下小伙伴 3 。所以小伙伴 3 是游戏的获胜者。
解题思路:
这题直接暴力求解了,先用数组依次存储每个小伙伴的编号,比如n等于6时,peo数组为{1,2,3,4,5,6},这时我们只需要进行n-1轮,即5轮游戏,就可以找出胜利者。
因此我们循环n-1次就行,除了第1次是从下标为0的元素开始计数,其余都是从上一轮被踢玩家的下一个玩家(未被踢)开始计数,需要注意,当循环计数到数组最后一个元素时,下一个元素是首元素。为了区分被踢玩家与尚存玩家,我们将被踢的玩家直接置0,遍历到这个位置的时候就知道这个位置的玩家已经被踢了,直接到下一个位置,直到计数到k,就把该位置元素置0。最后遍历数组,遇到不为0的元素,就是剩下的获胜者,返回即可。
代码如下:
int findTheWinner(int n, int k)
{
int peo[n],i,cnt=0,start;
for(i=0;i<n;i++)
{
peo[i]=i+1;
}
while(cnt<n-1) //进行n-1轮游戏,剩下的就是获胜者
{
if(cnt==0) //第一轮游戏,从玩家0开始计数,玩家k-1被踢出游戏
{
peo[k-1]=0;
start=k; //从被踢玩家k-1的下一个玩家开始
if(start==n) //若玩家k-1是最后一位玩家,则其下一位玩家是玩家0
start=0;
}
else
{
i=k; //每轮游戏都要计数k次
while(i>1)
{
if(peo[start]>0) //当前位置尚存玩家,则位置++,计数--
{
start++;
i--;
}
else //当前位置是被踢玩家,则位置++
{
start++;
}
if(start==n) //若上一位置是末尾,则改到首位
start=0;
}
while(peo[start]==0)
{
start++;
if(start==n)
start=0;
}
peo[start]=0;
start++;
if(start==n)
start=0;
}
cnt++;
}
for(i=0;i<n;i++)
{
if(peo[i])
break;
}
return i+1;
}