我想通过几个测试用例获得两个数组的子集。我不想使用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);
答案 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)
是第一个列表的长度。这是因为我们永远不会包含第一个数组中不存在的任何键,因为它与我们正在执行的检查无关。