假设我有三个列表:
list1 = a,c,d,r,t
list2 = a,d,t
list3 = a,r,d
然后 list2 包含在 list1 中,但 list3 不是因为它的顺序不同。
我在Apache Commons中检查了isSubCollection()
CollectionUtils
和containsAll()
方法,但似乎他们不考虑订单。
答案 0 :(得分:4)
boolean isSubsequence(List<?> sup, List<?> sub) {
int current = 0;
for (Object obj: sup) {
if (current == sub.size()) {
return true;
}
if (obj.equals(sub.get(current)) {
current++;
}
}
return current == sub.size();
}
此算法是线性的,在sup
列表中只需要1次迭代。
<强>更新强>
如果使用链接列表,则get
操作可以在O(n)中运行。所以你可以使用2个迭代器:
boolean isSubsequence(List<?> sup, List<?> sub) {
Iterator<?> supIt = sup.iterator();
for (Iterator<?> subIt = sub.iterator(); subIt.hasNext();) {
Object current = subIt.next();
boolean found = false;
while (supIt.hasNext() && !found) {
found |= supIt.next().equals(current);
}
if (!found) {
return false;
}
}
return true;
}
但看起来更丑陋。
答案 1 :(得分:0)
效率不高但是......
您可以在list2中抓取一个项目并迭代list1,直到找到它或到达列表末尾。如果找到了,请将索引保存在找到它的位置。
在list2中前进,并从第一个索引前进迭代list1。
如果你到了list2的末尾,它就是你的标准的子列表。
如果你到了list1的末尾并没有exausted list2,那就不是。
答案 2 :(得分:0)
自己鞭打起来并不困难。
boolean isSubSequence(List<?> sup, List<?> sub) {
for (Object o : sub) {
int index = sup.indexOf(o);
if (index == -1) { return false; }
sup = sup.subList(index + 1, sup.size());
}
return true;
}
这需要时间O(sup.size()+ sub.size()),这通常是最佳的。
答案 3 :(得分:0)
此处所需的方法与语言无关,但您至少需要确保可能来实现您的Java目标。使用C或C ++语言中的指针更容易描述解决方案,但我会尝试在这里使用更通用的术语。
从“包含列表”的第一个字符和“包含列表”开始。
如果两个字符匹配,则前进到两个列表的下一个字符。
如果您到达“包含列表”的末尾,答案是肯定的, 包含在另一个列表中。
否则,如果您到达“包含列表”的末尾,则答案为否,不包含“包含列表”。
否则,请使用两个当前当前字符重复此过程。
否则,前进到“包含列表”的下一个字符,然后再次尝试“包含列表”的相同字符。
如果到达“包含列表”的末尾,则答案为否,不包含“包含列表”。
否则,请使用两个当前当前字符重复此过程。
如果您在纸张上的每个列表中的字符上绘制两个箭头(“指针”),并且只有当它与“包含列表”中的字符匹配时才会将“包含列表”中的箭头向右碰撞,并且将每个步骤中的“包含列表”中的箭头向右移动,您将看到匹配成功与失败的可能性如何发挥作用。