我正在尝试使用n次算法来识别数组中最接近的匹配对。
我在下面的副本中创建了一个解决方案,但是我不确定这是什么大问题。我想也许是(Onlogn)或O(logn)。如果可能的话,我希望将其恢复为O(n)时间。
let closestMatchingPair = function(array) {
if(!array || array.length < 2) {
return 'invalid data get bent';
}
let pairFound = false;
let position1 = 0;
let position2 = 0;
let distance = array.length;
object = {};
//build object
for(let i = 0; i < array.length; i++) {
if(!object[array[i]]) {
object[array[i]] = [i];
} else {
object[array[i]].push(i);
}
}
//loop over object properties
for(let i = 0; i < array.length-1; i++) {
if(object[array[i]].length >= 2) {
var closest = object[array[i]].filter(a => a > i).shift();
if(distance > (closest - i)) {
position1 = i;
position2 = closest;
distance = closest - i;
pairFound = true;
}
}
}
return {
pairFound: pairFound,
position1: position1,
position2: position2,
distance: distance
}
}
//example [1] = 'invalid data get bent'
//example [1,2] = { pairFound: false, position1: 0, position2: 0, distance: 2 }
//example [1,2,1] = { pairFound: true, position1: 0, position2: 2, distance: 2 }
//example [1,2,1,3,2,2] = { pairFound: true, position1: 4, position2: 5, distance: 1 }
let array = [1,2,1,3,2,2];
console.log(closestMatchingPair(array));
https://repl.it/@zack_fanning/PushyGoodnaturedOutput
按预期工作,希望尽可能避免在第22行使用过滤器
var closest = object[array[i]].filter(a => a > i).shift();
答案 0 :(得分:2)
您正在做很多不必要的工作。事先构建一个对象通常是一个好主意,但是在这种情况下这不是胜利。您只需要对数组进行一次迭代,就需要在迭代之间跟踪以下事实:
prevPositions
–用于跟踪到目前为止看到的每个项目的最新索引的对象。distance
–迄今为止任何一对之间的最小距离。position1
,position2
–到目前为止距离最小的那对索引。(从技术上讲,distance
总是可以通过从position1
中减去position2
来计算得出的,但是我们通过单独存储来节省一些工作。)
在每次迭代中,您需要:
distance
中,并将当前和以前出现的索引存储在position1
和position2
中。prevPositions
中。遍历每个项目一次之后,position1
,position2
和distance
将包含最接近的一对索引以及它们之间的距离。
这是 O ( n )。您可以在下面的代码段中看到JavaScript的外观。
function closestMatchingPair(array) {
if (array.length < 2) {
throw new Error('Input must have at least two items');
}
// An object to track the most recent positions of the items we've seen so far
const prevPositions = {};
// Variables to track the smallest distance so far and corresponding indexes
let distance, position1, position2;
for (let index = 0; index < array.length; index++) {
const currentItem = array[index];
if (currentItem in prevPositions) {
// We've seen this item before; check if the distance from the previous
// instance is less than the smallest distance we've seen so far
const currentDistance = index - prevPositions[currentItem];
if (!distance || currentDistance < distance) {
// New smallest distance; update our variables
distance = currentDistance;
position1 = prevPositions[currentItem];
position2 = index;
if (currentDistance === 1) {
// Can't do any better than 1; no reason to continue
break;
}
}
}
prevPositions[currentItem] = index; // Save item's index
}
return { pairFound: !!distance, position1, position2, distance };
}
test([1]);
test([1,2]);
test([1,2,1]);
test([1,2,1,3,2,2]);
function test(input) {
console.log('input:', input);
try {
console.log('output:', closestMatchingPair(input));
} catch (e) {
console.error(e.message);
}
}
.as-console-wrapper{min-height:100%}
注意:该代码对prevPositions
使用普通对象。只要您的输入数组仅包含数字或字符串,就可以正常工作。但是,如果您输入的是[1, '1']
这两个值将被视为相等,因为当用作对象属性名称时,数字键被强制转换为字符串。 (从技术上讲,它要复杂一些,但是您可以理解。)如果您希望将它用于混合数组,则需要使用Map而不是对象。
答案 1 :(得分:0)
此行
for(let i = 0; i < array.length-1; i++) {
看起来很浪费。对于输入数组let array = [1,2,1,3,2,2]
,您将迭代整个过程。再次检查object[1]
,object[2]
,object[1]
,等等。
相反,通过object
的键进行迭代。
答案 2 :(得分:0)
您可以尝试一下。这段代码更好理解。您可以跳过行号。您的代码中的22。实际上,这是您的代码进行了一些更改。而且这段代码的复杂性肯定是O(n)。
let closestMatchingPair = function(array) {
if(!array || array.length < 2) {
return 'invalid data get bent';
}
let pairFound = false;
let position1 = 0;
let position2 = 0;
let distance = array.length;
object = {};
//build object
for(let i = 0; i < array.length; i++) {
if(!object[array[i]]) {
object[array[i]] = [i];
} else {
object[array[i]].push(i);
}
}
//loop over object properties
for(x in object) {
var item = object[x];
for(let i=1; i<item.length; i++){
if(item[i]-item[i-1] < distance){
pairFound = true;
position1 = item[i-1],
position2 = item[i],
distance = item[i]-item[i-1];
}
}
}
return {
pairFound: pairFound,
position1: position1,
position2: position2,
distance: distance
}
}
//example [1] = 'invalid data get bent'
//example [1,2] = { pairFound: false, position1: 0, position2: 0, distance: 2 }
//example [1,2,1] = { pairFound: true, position1: 0, position2: 2, distance: 2 }
//example [1,2,1,3,2,2] = { pairFound: true, position1: 4, position2: 5, distance: 1 }
let array = [1,2,1,3,2,2];
closestMatchingPair(array);
您也可以在这里link