如何在对数时间内检查具有相等值的对象是否在容器中

时间:2018-02-02 19:40:49

标签: javascript algorithm time-complexity

我想看看具有相等值的对象是否在对数时间内位于容器中。

我想拥有以下功能:

const a = [];

const el1 = {name: 'name1', directive: 'directive1'};
const el2 = {name: 'name2', directive: 'directive2'};
const el3 = {name: 'name3', directive: 'directive3'};
const b = {name: 'name1', directive: 'directive1'};

a.push(el1);
a.push(el2);
a.push(el3);


if(a.some(el => (el.name === b.name && el.directive === b.directive ))) {
  console.log("YES!");
} else {
  console.log("NO!");
}

这给了我想要的结果。但是,这是O(N)时间。

const s = new Set();

const el1 = {name: 'name1', directive: 'directive1'};
const el2 = {name: 'name2', directive: 'directive2'};
const el3 = {name: 'name3', directive: 'directive3'};
const b = {name: 'name1', directive: 'directive1'};

s.add(el1);
s.add(el2);
s.add(el3);

if(s.has(b)) {
  console.log("YES!");
} else {
  console.log("NO!");
}

这是O(logN),但结果不是我想要的。

那么我可以使用什么样的Javascript数据结构在上面的代码中打印YES并且会有复杂度O(logN)? (我不想自己实现数据结构)

4 个答案:

答案 0 :(得分:3)

您可以使用按名称键入的Map,其中相应的值是一组指令:

const elements = [
    {name: 'name1', directive: 'directive1'},
    {name: 'name2', directive: 'directive2'},
    {name: 'name3', directive: 'directive3'}
];

const map = new Map(elements.map(({name}) => [name, new Set]));
elements.forEach(({name, directive}) => map.get(name).add(directive));

const b = {name: 'name1', directive: 'directive1'};

if (map.has(b.name) && map.get(b.name).has(b.directive)) {
    console.log("YES!");
} else {
    console.log("NO!");
}

答案 1 :(得分:1)

假设:数组a按字典顺序排序,即只要a[i]<a[j]

a[i].name<a[j].name || (a[i].name==a[j].name && a[i].description<a[j].description))

这是一个具有对数复杂度的二进制搜索:

&#13;
&#13;
const a = [];
for (i = 0; i < 100000; i++) {
  si = String(i);
  el = {
    name: 'name' + si,
    directive: 'directive' + si
  };
  a.push(el);
}

const b = {
  name: 'name70000',
  directive: 'directive70000'
};


var c = 0; // counter 

// binary search
function binary_search(a, b) {
  c++;
  var l = 0;
  var r = a.length - 1;
  if (l > r) {
    return false;
  }
  m = Math.floor((l + r) / 2);
  if ((a[m].name < b.name) || (a[m].name == b.name && a[m].directive < b.directive)) {
    return binary_search(a.slice(m + 1), b);
  } else if ((a[m].name > b.name) || (a[m].name == b.name && a[m].directive > b.directive)) {
    return binary_search(a.slice(0, m), b);
  } else {
    return true;
  }
}



found = binary_search(a, b);
console.log(found, "in " + String(c) + " steps");
&#13;
&#13;
&#13;

答案 2 :(得分:0)

我们可以使用Array作为数据结构。考虑到我们可以使用递归对数时间函数,通过确定父字段部分的端点和递归来沿多个维度排序(或找到插入/删除的位置)。

让我们说我们的尺寸是脚手架:name -> directive -> third_property

首先根据name对数组进行排序。现在,在name时间内找到每个log n部分,并根据directive快速排序该部分,类似于third_property。然后要查找元素,请使用类似的二进制搜索,首先查找name属性的范围,然后在directive上使用该范围内的二进制搜索,依此类推。

或者通过为我们可以排序和二元搜索的每个元素创建一个键来绕过所有这些:element.key = element.name + element.directive:)

答案 3 :(得分:-2)

  

不要看这个答案的负面分数。使用它并享受。它很简单,在O(logN)中效果很好。

它返回false,因为它们(el1b)是不同的对象引用。您可以按b填写el1但如果您希望使用O(logN)进行搜索的简单方法,则可以使用以下代码:

&#13;
&#13;
var orderObj = function(unordered){
   const ordered = {};
   Object.keys(unordered).sort().forEach(function(key) {
       ordered[key] = unordered[key];
    });
    return ordered;
}
Set.prototype.addIt = function(item){s.add(JSON.stringify(orderObj(item)));}
Set.prototype.hasIt = function(item){return s.has(JSON.stringify(orderObj(item)));}
    
//-------------------------------------

const s = new Set();

const el1 = {name: 'name1', directive: 'directive1'};
const el2 = {name: 'name2', directive: 'directive2'};
const el3 = {name: 'name3', directive: 'directive3'};

const b = {name: 'name1', directive: 'directive1'};
const c = {directive: 'directive3', name: 'name3'};

s.addIt(el1);
s.addIt(el2);
s.addIt(el3);

s.hasIt(b)
 ?console.log("YES!")
 :console.log("NO!");

s.hasIt(c)
 ?console.log("YES!")
 :console.log("NO!");
&#13;
&#13;
&#13;

<强>更新

我更新了我的答案,现在它支持具有不同订单的对象。正如您在上面的示例中所看到的,cel3的顺序不同,但脚本返回Yes结果;)