在进行代码战训练时,我遇到了有关约瑟夫置换的挑战,我尝试先在纸上解决它,然后将其翻译为代码。
问题如下: “创建一个返回约瑟夫斯(Josephus)排列的函数,将要排列的项目的初始数组/列表作为参数,就好像它们是一个圆形,并计数出每k个位置,直到没有剩余为止。”
我的主要想法是:
使用两个迭代器:
在0处初始化i,在1处初始化k
function josephus(items,step){
var output = [];
var i = 0;
var k = 1;
if( items == [] ) {
return [];
}
while (items.length != 1) {
if (k == step && i == items.length - 1) {
output.push(items[i]);
items.splice(i, 1);
i = 0;
k = 1;
} else if (k == step && i != items.length - 1) {
output.push(items[i]);
items.splice(i, 1);
k = 1
} else if (k < step && i == items.length - 1) {
k++;
i=0;
} else if (k < step && i != items.length - 1) {
k++;
i++;
}
}
output.push(items[0]);
return output;
}
这可行,但是效率不高,当我在运行样本测试中运行它时,我已经通过了5个样本测试,但它还包含一个STDERR:执行超时(12000毫秒)。
样本测试如下:
Test.assertSimilar(josephus([1,2,3,4,5,6,7,8,9,10],1),[1,2,3,4,5,6,7,8,9,10])
Test.assertSimilar(josephus([1,2,3,4,5,6,7,8,9,10],2),[2, 4, 6, 8, 10, 3, 7, 1, 9, 5])
Test.assertSimilar(josephus(["C","o","d","e","W","a","r","s"],4),['e', 's', 'W', 'o', 'C', 'd', 'r', 'a'])
Test.assertSimilar(josephus([1,2,3,4,5,6,7],3),[3, 6, 2, 7, 5, 1, 4])
Test.assertSimilar(josephus([],3),[])
我的问题是,我该如何提高效率?
使用的算法是错误的还是实现?
一条评论提到了两件事:
push()非常慢,这是我的一种可能(错误的数据结构)
建议查看递归(这对我对算法的怀疑更多)。不过,我并没有真正看到如何使它递归。
在此先感谢您的帮助!
答案 0 :(得分:0)
有一个重复发生,可以记录下来。 (这似乎通过了Codewars测试。)
function g(n, k, i, memo){
if (memo.hasOwnProperty([n, k, i]))
return memo[[n, k, i]];
if (i == 1)
return memo[[n, k, i]] = (k - 1) % n;
return memo[[n, k, i]] =
(k + g(n - 1, k, i - 1, memo)) % n;
}
function f(A, k){
let n = A.length;
let result = new Array(n);
let memo = {};
for (let i=1; i<=n; i++)
result[i - 1] = A[ g(n, k, i, memo) ];
return result;
}
let str = '';
str += JSON.stringify(f([1,2,3,4,5,6,7,8,9,10],1)) + '\n';
//[1,2,3,4,5,6,7,8,9,10])
str += JSON.stringify(f([1,2,3,4,5,6,7,8,9,10],2)) + '\n';
//[2, 4, 6, 8, 10, 3, 7, 1, 9, 5])
str += JSON.stringify(f(["C","o","d","e","W","a","r","s"],4)) + '\n';
//,['e', 's', 'W', 'o', 'C', 'd', 'r', 'a'])
str += JSON.stringify(f([1,2,3,4,5,6,7],3)) + '\n';
//,[3, 6, 2, 7, 5, 1, 4])
str += JSON.stringify(f([],3))
//,[])
console.log(str);
为解释重复发生,删除的第一个元素(当i = 1
时)显然是(k - 1) mod n
(零索引)。现在考虑找到g(n, k, i)
。被删除的第一个元素是(k - 1) mod n
,然后我们从第k
位开始。因此,问题在于找到第(i - 1)
个元素,然后从(k - 1) mod n
处删除元素并从k
(即(k + g(n - 1, k, i - 1)) mod n
)开始删除。
答案 1 :(得分:0)
您可以将起始位移到末尾。
const josephus = (x) => parseInt(x.toString(2).substr(1) + 1, 2);
答案 2 :(得分:-1)
您是否尝试过实施功能性方法? 来自wikipedia:
function getSafePosition(n) {
// find value of L for the equation
valueOfL = n - highestOneBit(n);
safePosition = 2 * valueOfL + 1;
return safePosition;
}
function highestOneBit(i) {
i |= (i >> 1);
i |= (i >> 2);
i |= (i >> 4);
i |= (i >> 8);
i |= (i >> 16);
return i - (i >> 1);
}
这应该在O(n)中运行