2つの配列をソートし、両方の要素を比較して比較します。サブバッグ候補の要素がスーパーバッグに見つからない場合、前者はサブバッグではない。一般的にO(n * log(n))のソートはO(max * log(n))であり、O(max * s)の合計時間計算量はsとtである。 (m))であり、ここで、m = max(s、t)である。
function superbag(sup, sub) {
sup.sort();
sub.sort();
var i, j;
for (i=0,j=0; i<sup.length && j<sub.length;) {
if (sup[i] < sub[j]) {
++i;
} else if (sup[i] == sub[j]) {
++i; ++j;
} else {
// sub[j] not in sup, so sub not subbag
return false;
}
}
// make sure there are no elements left in sub
return j == sub.length;
}
実際のコード内の要素が整数である場合、あなたは、全体的なO(MAX(S、T))の時間複雑さのために(例えばradix sortなど)専用の整数ソートアルゴリズムを使用できるかどうかのバッグが小さい場合、組み込みのArray.sort
はカスタム整数型ソートよりも高速に実行される可能性が高くなります。
潜在的に時間の複雑さが低い可能性のある解決策は、バッグタイプを作成することです。完全なバッグは特に簡単です。バッグの既存の配列を反転させます:整数またはキーを持つオブジェクトまたは配列を作成し、値の繰り返し回数を作成します。配列を使用すると、arrays are sparse in Javascriptという名前をつけることでスペースを無駄にすることはありません。サブバッグまたはスーパーバッグのチェックには、バッグ操作を使用できます。たとえば、サブ候補からスーパーを減算し、結果が空でないかどうかをテストします。あるいは、contains
の操作はO(1)(またはおそらくO(log(n)))でなければならないので、サブバッグ候補をループし、スーパーバッグ格納容器が各サブバッグのサブバッグ格納容器を超えているかどうかをテストする要素はO(n)またはO(n * log(n))でなければなりません。
以下はテストされていません。実装としてisInt
が残っています。
function IntBag(from) {
if (from instanceof IntBag) {
return from.clone();
} else if (from instanceof Array) {
for (var i=0; i < from.length) {
this.add(from[i]);
}
} else if (from) {
for (p in from) {
/* don't test from.hasOwnProperty(p); all that matters
is that p and from[p] are ints
*/
if (isInt(p) && isInt(from[p])) {
this.add(p, from[p]);
}
}
}
}
IntBag.prototype=[];
IntBag.prototype.size=0;
IntBag.prototype.clone = function() {
var clone = new IntBag();
this.each(function(i, count) {
clone.add(i, count);
});
return clone;
};
IntBag.prototype.contains = function(i) {
if (i in this) {
return this[i];
}
return 0;
};
IntBag.prototype.add = function(i, count) {
if (!count) {
count = 1;
}
if (i in this) {
this[i] += count;
} else {
this[i] = count;
}
this.size += count;
};
IntBag.prototype.remove = function(i, count) {
if (! i in this) {
return;
}
if (!count) {
count = 1;
}
this[i] -= count;
if (this[i] > 0) {
// element is still in bag
this.size -= count;
} else {
// remove element entirely
this.size -= count + this[i];
delete this[i];
}
};
IntBag.prototype.each = function(f) {
var i;
foreach (i in this) {
f(i, this[i]);
}
};
IntBag.prototype.find = function(p) {
var result = [];
var i;
foreach (i in this.elements) {
if (p(i, this[i])) {
return i;
}
}
return null;
};
IntBag.prototype.sub = function(other) {
other.each(function(i, count) {
this.remove(i, count);
});
return this;
};
IntBag.prototype.union = function(other) {
var union = this.clone();
other.each(function(i, count) {
if (union.contains(i) < count) {
union.add(i, count - union.contains(i));
}
});
return union;
};
IntBag.prototype.intersect = function(other) {
var intersection = new IntBag();
this.each(function (i, count) {
if (other.contains(i)) {
intersection.add(i, Math.min(count, other.contains(i)));
}
});
return intersection;
};
IntBag.prototype.diff = function(other) {
var mine = this.clone();
mine.sub(other);
var others = other.clone();
others.sub(this);
mine.union(others);
return mine;
};
IntBag.prototype.subbag = function(super) {
return this.size <= super.size
&& null !== this.find(
function (i, count) {
return super.contains(i) < this.contains(i);
}));
};
は、オブジェクトの集合の実装例については、「comparing javascript arrays」も参照してください、あなたは今までの要素の繰り返しを禁止したいはずです。
最後の例はfalseを返す必要があります。 2つの配列の長さが同じ場合、スーパー/サブセットはありません。 http://mathworld.wolfram.com/Superset.html – Bakudan
セットには重複要素を含めることはできません。そのため、これらの条件でスーパーセットであることを判断するという概念はあまり意味がありません。 –
最後の例は、2つの理由から、 'true'でなければなりません:(1)繰り返しは' {1,1} = {1} 'のセットでは関係ありません。 (2)集合はそれ自身の部分集合とスーパー集合である。 2つが等しくないと思われる場合は、「適切なサブセット」および「適切なスーパーセット」と呼ばれます。 – outis