五个朋友正在排队喝魔性可乐。当第一个朋友喝下可乐时,他消失了,并复制成两份!在那之后,这些新的副本进入行的末尾,下一个朋友喝下神奇的可乐,重复这个过程。
例如,假设我们有以下朋友:
[Sheldon, Leonard, Penny, Rajesh, Howard]
Sheldon喝了第一杯可乐后,队伍会是这样的:
[Leonard, Penny, Rajesh, Howard, Sheldon, Sheldon]
伦纳德喝了可乐后,队伍变成这样:
[Penny, Rajesh, Howard, Sheldon, Sheldon, Leonard, Leonard]
等等…
我的目标是用JavaScript编写一个函数,给定一个数组,其中包含行中的人名和数字N,它将返回喝神奇可乐的第N个人的名字。
因此,例如,执行console.log(whoIsNext([Sheldon, Leonard, Penny, Rajesh, Howard], 1))
应该返回Sheldon
。
为了实现这一点,我制作了以下代码:
function whoIsNext(names, r){
var fistInLine;
if(r <= names.length){
return names[r-1];
}else{
while(r > names.length){
fistInLine = names.shift();
names.push(fistInLine, fistInLine);
}
return names[r-1];
}
}
此功能适用于以下情况:
names = ["Sheldon", "Leonard", "Penny", "Rajesh", "Howard"];
Test.assertEquals(whoIsNext(names, 1), "Sheldon");
但测试失败:
names = ["Sheldon", "Leonard", "Penny", "Rajesh", "Howard"];
Test.assertEquals(whoIsNext(names, 52), "Penny");
如果我尝试使用一个非常大的数字,比如:
names = ["Sheldon", "Leonard", "Penny", "Rajesh", "Howard"];
Test.assertEquals(whoIsNext(names, 7230702951), "Leonard");
它甚至不会停止运行(需要很长时间)。
很明显,我的解决方案不仅不正确,而且似乎也不够有效。我该怎么修?
一个基于零的递归建议,它返回数组的索引,这里的长度为base = 5
。
1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 number 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 index 0 1 2 3 4 0 0 1 1 2 2 3 3 4 4 0 0 0 0 1 1 1 1 2 2 2 2 3 3 3 3 4 4 4 4 0 0 0 0 0
它变得可见,图案以5为基础,每一轮都会增加因子2。
5 -> 10- > 20 -> 40
计算示例
Array after step 0 1 2 3 4 5 6 7 8 9 0: 0 Sheldon | 1: 1 Leonard | | 2: 2 Penny | | | 3: 3 Rajesh | | | | 4: 4 Howard | | | | | 5: 0 Sheldon | | | | | 6: 0 Sheldon | | | | | | 7: 1 Leonard | | | | | | 8: 1 Leonard | | | | | | | 9: 2 Penny | | | | | | 10: 2 Penny | | | | | | 11: 3 Rajesh | | | | | 12: 3 Rajesh | | | | | 13: 4 Howard | | | | 14: 4 Howard | | | | 15: 0 Sheldon | | | 16: 0 Sheldon | | | 17: 0 Sheldon | | 18: 0 Sheldon | | 19: 1 Leonard | 20: 1 Leonard | 21: 1 Leonard 22: 1 Leonard
var friends = ['Sheldon', 'Leonard', 'Penny', 'Rajesh', 'Howard'],
base = friends.length;
function getIndex(n, i) {
i = i || base;
if (n < i) {
return Math.floor(n * base / i);
}
return getIndex(n - i, 2 * i);
}
var i = 0, index;
document.write(friends[getIndex(1 - 1)] + '<br>'); // "Sheldon"
document.write(friends[getIndex(52 - 1)] + '<br>'); // "Penny"
document.write(friends[getIndex(7230702951 - 1)] + '<hr>'); // "Leonard"
for (i = 0; i < 200; i++) {
index = getIndex(i);
document.write(i + ': ' + index + ' ' + friends[index] + '<br>');
}
好吧,开始吧,这是一个非常简单的方法,我会想出一个更好的方法(我已经想了一半,我只需要把它组合在一起)
function whoIsNext(names, index, multiplyFactor)
{
var count = names.length;
var fullLoops = 0;
var currIndex = 0;
while(currIndex <= index)
{
for(var i = 0; i < count; i++)
{
currIndex += Math.pow(multiplyFactor, fullLoops);
if(currIndex > index)
{
return names[i];
}
}
fullLoops++;
}
}
这个想法是,每次人们做一个完整的循环(countPerson = Math.pow(2, countFullLoops)
),同一个人来的数量就会翻倍。如果你在设定指数之前积累人数,直到达到指数,你就会找到合适的人(我觉得我只是解释了一件非常简单的事情,非常困难)。
此外,你可以根据自己的意愿替换任何输入(改变开始时的人数,改变乘法系数(有人说是四倍可乐吗?))。