Java 高效生成三重态组合
给定一组三元组S,其中对于S中的每个三元组S,S[1]>=S[2]>=S[3],其中S[i]是三元组S的第i个元素。对于s中的任何s,t,v,让函数F(s,t,v)生成一个新的三元组:F(s,t,v)=(max{s[1],t[1],v[1]},max{s[2],t[2],v[2]},max{s[3],t[3],v[3]})。目标:高效地生成集T={F(s,T,v)| s,T,v\in s} 两个例子:Java 高效生成三重态组合,java,algorithm,Java,Algorithm,给定一组三元组S,其中对于S中的每个三元组S,S[1]>=S[2]>=S[3],其中S[i]是三元组S的第i个元素。对于s中的任何s,t,v,让函数F(s,t,v)生成一个新的三元组:F(s,t,v)=(max{s[1],t[1],v[1]},max{s[2],t[2],v[2]},max{s[3],t[3],v[3]})。目标:高效地生成集T={F(s,T,v)| s,T,v\in s} 两个例子: S = [(9,4,3),(8,6,2),(6,6,4)] T = [(9,4,3),(8,6
S = [(9,4,3),(8,6,2),(6,6,4)]
T = [(9,4,3),(8,6,2),(6,6,4),(9,6,3),(9,6,4),(8,6,4)]
S = [(9,4,3),(8,6,2),(6,5,4)]
T = [(9,4,3), (9,6,3), b(9,5,4), b(9,6,4), b(8,6,2), b(8,6,4), b(6,5,4)]
下面是一个实现上述功能的简单但相对低效的实现。这段代码在O(n^3)中运行,其中| S |=n。问题是:如何更有效地实现这一点?这将涉及到建立一个有效的数据结构来保存S的排序版本。例如,我们可以观察到F(S,t,v)=S如果t[1],v[1]我怀疑还有很多可以获得的。我提出我的尝试
- 考虑只由两个三元组组成的类似组合的函数F2(s,t)。现在F(s,t,v)可以写为F2(s,F2(t,v)),通过这种方式将F2(t,v)的结果用于不同的s来计算,可能会有性能增益
- 通过估计结果
的容量,可能会有轻微的改进,因此不需要进行扩展和重新灰化HashSet
public static Set<Triple> gen(List<Triple> s) {
// Deduplicate s
s = new ArrayList<>(new HashSet<>(s));
int n = s.size();
// Combine pairs of triplets first
int maxSizeOfT2 = (n * n - 1) / 2;
int capacityForT2 = (maxSizeOfT2 * 4 + 2) / 3;
Set<Triple> t2AsSet = new HashSet<>(capacityForT2);
// For the pairs only pair two *different* triples
for (int i = 0; i < s.size(); i++) {
for (int j = i + 1; j < s.size(); j++) {
Triple newTriplet = f2(s.get(i), s.get(j));
t2AsSet.add(newTriplet);
}
}
List<Triple> t2 = new ArrayList<>(t2AsSet);
// For the combinations of three original triplets
// combine every pair with ever original triplet
int maxSizeOfT = (t2AsSet.size() + 1) * (n + 1) - 1;
int capacityForT = (maxSizeOfT * 4 + 2) / 3;
Set<Triple> t = new HashSet<>(capacityForT);
for (int i = 0; i < t2.size(); i++) {
for (int j = 0; j < s.size(); j++) {
Triple newTriplet = f2(t2.get(i), s.get(j));
t.add(newTriplet);
}
}
// Instead of generating F(s, s, s) just add every s to the result
t.addAll(s);
return t;
}
在评论中,您期望最好的案例可以得到改进,数字可能表明这是事实。在最坏的情况下,似乎只有轻微的改善
正如我在评论中所说的,结果集的大小是O(n^3),因此生成它的任何算法都不会比O(n^3)快。我们可能希望在n^3上有一个更小的常数因子。在我看来,新集合中可能有O(n^3)个元素。如果是这样,那么生成它的速度就不能超过O(n^3)。@OleV.V。我同意,最坏情况下的运行时复杂性不会提高,但平均/最佳情况下的复杂性肯定会提高。特别是使用正确的数据结构来保持三元组的排序。您可能需要澄清这个问题。我来自首都O,这意味着最糟糕的情况。另外,如果有人可以减少一些运行时间的因素,使其更短,但仍然是O(n^3),您有兴趣吗?
public static Set<Triple> gen(List<Triple> s) {
// Deduplicate s
s = new ArrayList<>(new HashSet<>(s));
int n = s.size();
// Combine pairs of triplets first
int maxSizeOfT2 = (n * n - 1) / 2;
int capacityForT2 = (maxSizeOfT2 * 4 + 2) / 3;
Set<Triple> t2AsSet = new HashSet<>(capacityForT2);
// For the pairs only pair two *different* triples
for (int i = 0; i < s.size(); i++) {
for (int j = i + 1; j < s.size(); j++) {
Triple newTriplet = f2(s.get(i), s.get(j));
t2AsSet.add(newTriplet);
}
}
List<Triple> t2 = new ArrayList<>(t2AsSet);
// For the combinations of three original triplets
// combine every pair with ever original triplet
int maxSizeOfT = (t2AsSet.size() + 1) * (n + 1) - 1;
int capacityForT = (maxSizeOfT * 4 + 2) / 3;
Set<Triple> t = new HashSet<>(capacityForT);
for (int i = 0; i < t2.size(); i++) {
for (int j = 0; j < s.size(); j++) {
Triple newTriplet = f2(t2.get(i), s.get(j));
t.add(newTriplet);
}
}
// Instead of generating F(s, s, s) just add every s to the result
t.addAll(s);
return t;
}
List Element Result Your time My time Improvement
size range size milliseconds milliseconds %
-----------------------------------------------------------------
3 1–9 6 0.038 0.015 60
3 1–10 000 7 0.046 0.016 66
400 1–9 159 4736 4740 0
400 1–10 000 858 897 1079 1067 1