从 找出游戏的获胜者 中引发的思考

题目描述

共有 n 名小伙伴一起做游戏。小伙伴们围成一圈,按 顺时针顺序 从 1 到 n 编号。确切地说,从第 i 名小伙伴顺时针移动一位会到达第 (i+1) 名小伙伴的位置,其中 1 <= i < n ,从第 n 名小伙伴顺时针移动一位会回到第 1 名小伙伴的位置。

游戏遵循如下规则:

    从第 1 名小伙伴所在位置 开始 。
    沿着顺时针方向数 k 名小伙伴,计数时需要 包含 起始时的那位小伙伴。逐个绕圈进行计数,一些小伙伴可能会被数过不止一次。
    你数到的最后一名小伙伴需要离开圈子,并视作输掉游戏。
    如果圈子中仍然有不止一名小伙伴,从刚刚输掉的小伙伴的 顺时针下一位 小伙伴 开始,回到步骤 2 继续执行。
    否则,圈子中最后一名小伙伴赢得游戏。

给你参与游戏的小伙伴总数 n ,和一个整数 k ,返回游戏的获胜者。

1 <= k <= n <= 500

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/find-the-winner-of-the-circular-game
 

具体示例请看官网。

 

题目思考

对于本问题,无非是在环形圈中按照一定的模式排除小伙伴,最后只剩下一个人。我们首先应该用数学的思想去思考这个问题,显而易见,对于一组n,k只会对应唯一一个小伙伴。我们先称这个小伙伴为m,则可以将上述内容用公式表为:f(n,k) = m,其中f代表一个函数或者一个模式,使得n,k能映射到正确的m。我们接下来的任务就是去思考或者总结归纳出这个f。那么这个f到底是怎样的一个函数或者模式呢?

1.我们先考察一组n,k所有的可能就是k个。

2.我们现设n=2,k=1,不难发现m=2,我们再设n=3,k=1也不难发现m=3,以此类推,当n=u,k=1时,m=u。那么当k=2时会是怎样的情况呢?答案是变得不容易发现规律。

3.设n=2,k=2,则m=1,当n=3,k=2时,m=2,当n=4,k=2时,m=1,当n=5, k=2时,m=3......

4.通过观察,我们还是很难发现这个n,k与m之间存在的这个f是什么,但是不难看出,f是单一函数的这个可能就可以排除了。可究竟是什么呢?这个答案就是,如果你没有相当强的数感,很难得出这个f究竟是什么,既然这样,我们应该尝试着换种思路。

5.我们试着将第一轮与第二轮,第二轮与第三轮等等的序列总结出一个映射关系,然后从中发现最后一轮剩下数的序列与上一轮的序列比较,然后通过这个映射公式与剩下的这个数建立关系式,详细的可以参考这篇文章,https://zhuanlan.zhihu.com/p/121159246,最终得出递推公式:f(n,k) = (f(n-1,k) + k) % i,其中f(1,k) = 0, 1<=i<=n;

6.虽然递归式能很好利用计算机解决问题,但这还不是最完美的,至今为止还没有证明出这个问题不能用一个特定函数来解决,也就是说这个问题有可能存在一个特定的函数,只是人们还没发现。当然笔者也在思考这个问题,如果存在一个特定函数的话,那也是一个不平常的函数,可能是一个积分式,可能会用到更高深的数学理论,但这想必是个很有趣的问题。

我们来看两个不同版本的代码吧,第一种是常规思路,第二种则是用递归方法,笔者一直在想第三种用特定函数解决,不过我想这可能有解,可能没解,这至少还没有谁能证明出来,我就暂且相信有吧。

第一种:

var findTheWinner = function(n, k) {
	var map = new Array(n+1);
        map.fill(0,0,n+2);
	var count = 0;
	var cur = 0;
	while(count < n-1)
        {
	    let skip = 0;
	    while(skip < k)
	    {
		if(cur >= n)
		{
                    cur = 0;
		}
	        if(map[cur+1] == 0)
	        {
		    skip++;
		    cur++;
		}else{
		    cur++;
	        }
	    }
	    if(map[cur] == 0){
		map[cur] = 1;
	        count++;
	    }
			
	}
	return map.indexOf(0,1);
};

   第二种:

var findTheWinner = function(n, k) {
    
    var f = 0;
    for(let i = 1; i <= n; i++) {
        f = (f+k) % i;
    }
    return f+1;
}

 

 

在Python实现一个简单的猜拳游戏,可以使用基本的控制流程和随机数生成。游戏规则如下:人和机器进行猜拳,每次出拳都是石头、剪刀、布的一种,连续胜三次的一方获胜。下面是一个简单的实现方法: ```python import random def get_computer_choice(): choices = ["石头", "剪刀", "布"] return random.choice(choices) def get_user_choice(): choice = input("请输入你的选择(石头、剪刀、布):") while choice not in ["石头", "剪刀", "布"]: choice = input("输入错误,请重新输入你的选择(石头、剪刀、布):") return choice def judge_winner(user_choice, computer_choice): if user_choice == computer_choice: return "平局" elif (user_choice == "石头" and computer_choice == "剪刀") or \ (user_choice == "剪刀" and computer_choice == "布") or \ (user_choice == "布" and computer_choice == "石头"): return "用户" else: return "电脑" def play_game(): user_wins = 0 computer_wins = 0 while user_wins < 3 and computer_wins < 3: user_choice = get_user_choice() computer_choice = get_computer_choice() print(f"电脑选择了:{computer_choice}") result = judge_winner(user_choice, computer_choice) if result == "用户": print("恭喜你赢了这一局!") user_wins += 1 elif result == "电脑": print("很遗憾,电脑赢了这一局。") computer_wins += 1 else: print("这一局是平局。") if user_wins == 3: print("恭喜你,最终获胜!") elif computer_wins == 3: print("电脑最终获胜!") play_game() ``` 这段代码首先导入了`random`模块来生成随机的电脑出拳选择。定义了获取用户和电脑选择的函数,以及判断胜负的函数。主函数`play_game`控制游戏流程,通过循环进行猜拳游戏,直到用户或电脑的一方先胜三次。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值