两个数组的isSubset

时间:2019-03-29 17:50:25

标签: javascript algorithm

我想通过几个测试用例获得两个数组的子集。我不想使用javascript .every函数,因为这太简单了。我的尝试可行,但我认为对于时间和空间复杂度O(n ^ 2)来说不是最佳选择。

我的测试用例如下:

1)array1的所有值都应在array2

中定义

2)如果array1中存在重复值,则array2中也应考虑它们。例如,如果arr1 = ["a", "a"]arr2 = ["b", "a"]则isSubset为false,因为"a"在第一个出现两次,而在第二个出现一次。

这是我的解决方法:

let arr1 = ["A", "B", "C"];
let arr2 = ["C", "A", "B", "D"];

function isSubset(a, b) {
  if(a.length > b.length) {
    return false;
  }

  var myHash = {};
  for (var i = 0; i < a.length; ++i) {
    if(myHash[a[i]]) {
      myHash[a[i]] += 1;
    } else {
      myHash[a[i]] = 1;
    }
  }

  var myHash2 = {};
  for (var i = 0; i < b.length; ++i) {
    if(myHash2[b[i]]) {
      myHash2[b[i]] += 1;
    } else {
      myHash2[b[i]] = 1;
    }
  }


  for(var i in myHash) {
    for(var j in myHash2) {
      if(i == j && myHash[i] > myHash2[j]) {
        return false;
      }
    }
  }


  return true;
}

// test
var a = ["B", "A", "C", "A"];
var b = ["A", "B", "C", "D"];
var c = isSubset(a, b);
console.log(c);

Codepen:https://codepen.io/anon/pen/KYPayp?editors=0010

3 个答案:

答案 0 :(得分:1)

您不需要嵌套循环,因为您已经计算了myHash2中的计数。只是看一下。将嵌套循环替换为

for(var i in myHash) {
  if (myHash[i] > myHash2[i])
    return false;
}

时间复杂度为: O(n),其中n是较大数组的长度。如果仅在密钥存在时(如 vivek_23 answer中所示),从myHash2中减去计数器,您也可以完全省去myHash

这也可以在 O(nlogn)+ O(n)中完成,其中n是较大数组的长度,不使用额外的内存。 O(n log n)用于排序。基本上,我们同时迭代两个数组,并在元素相等的情况下增加指针。如果arr2中的元素较大,则找不到元素,我们返回false。如果我们到达arr1的末尾,则会找到所有元素,然后返回true

function isSubset(arr1, arr2) {
  arr1 = arr1.sort();
  arr2 = arr2.sort();
  let idx1 = 0, idx2 = 0;
  while (idx1 < arr1.length) {
    if (idx2 >= arr2.length) {
      return false;
    }
    if (arr1[idx1] > arr2[idx2]) {
      idx2++;
    } else if (arr1[idx1] == arr2[idx2]) {
      idx1++; idx2++;
    } else {
      return false;
    }
  }
  return true;
}

答案 1 :(得分:1)

您可以获取一个哈希表,并对从第一个数组开始和从第二个数组开始的所有项目进行计数。如果所有计数均为零,则两个数组共享同一组。

function isSubset(a, b) {
    function count(array, inc) {
        var i = array.length;
        while (i--) hash[array[i]] = (hash[array[i]] || 0) + inc;
    }

    var hash = {}, i, keys;

    count(a, 1);
    count(b, -1);

    keys = Object.keys(hash);
    i = keys.length;
    while (i--) if (hash[keys[i]]) return false;
    return true;
}

console.log(isSubset(["B", "A", "C", "A"], ["A", "B", "C", "A"]));      //  true
console.log(isSubset(["B", "A", "C", "A"], ["A", "B", "C", "D"]));      // false
console.log(isSubset(["B", "A", "C", "A"], ["A", "B", "C", "D", "A"])); // false

答案 2 :(得分:0)

  • 您快到了。而不是制作两个不同的哈希对象,而制作一个哈希对象。使用第一个数组递增Self的值,使用另一个数组递减存储在hash中的值。

  • 现在,如果hash中存储的计数大于零,则表明数组hash中存在某个值的不足。否则,我们对子集目标都有好处。

b

  • 时间复杂度为function isSubset(a, b) { if(a.length > b.length) { return false; } var hash = {}; for(var i=0;i<a.length;++i){ if(hash[a[i]] === undefined) hash[a[i]] = 0; hash[a[i]]++; } for(var i=0;i<b.length;++i){ if(hash[b[i]] !== undefined) hash[b[i]]--; } var keys = Object.keys(hash); for(var each_key in keys){ if(hash[keys[each_key]] > 0) return false; } return true; } // test var a = ["B", "A", "C", "A"]; var b = ["A", "B", "C", "D"]; console.log(isSubset(a, b)); a = ["B", "A", "C", "A"]; b = ["A", "B", "C", "D","A"]; console.log(isSubset(a, b));,其中O(n + m)n是相应列表的长度。空间复杂度为m,其中O(n)是第一个列表的长度。这是因为我们永远不会包含第一个数组中不存在的任何键,因为它与我们正在执行的检查无关。