涉及范围的问题通常适用于使用树。这是一种使用方法TreeSet
:
public class DisjointChecker {
private final NavigableSet<Integer> integers = new TreeSet<Integer>();
public boolean check(int value) {
return integers.add(value);
}
public boolean check(int from, int to) {
NavigableSet<Integer> range = integers.subSet(from, true, to, true);
if (range.isEmpty()) {
addRange(from, to);
return true;
}
else {
return false;
}
}
private void addRange(int from, int to) {
for (int i = from; i <= to; ++i) {
integers.add(i);
}
}
}
在这里,这些方法不是调用错误处理程序,而是check
返回一个布尔值,指示参数是否与所有先前的参数不相交。范围版本的语义与原始代码中的不同;如果范围不是不相交的,则不添加任何元素,而在原始范围内,添加第一个非不相交元素以下的任何元素。
有几点可能需要详细说明:
Set::add
返回一个布尔值,指示添加是否修改了集合;我们可以将其用作方法的返回值。
NavigableSet
是一个晦涩但标准的子接口,SortedSet
遗憾的是它被忽略了。尽管您实际上可以在此处使用纯SortedSet
文本,只需进行少量修改。
- 该
NavigableSet::subSet
方法(如SortedSet::subSet
)返回限制在给定范围内的基础集的轻量级视图。这提供了一种非常有效的方式来查询树在一次操作中与整个范围的任何重叠。
- 这里的
addRange
方法非常简单,当将 m 个项目添加到之前已经查看过 n 个项目的检查器时,运行时间为 O(m log n)。可以通过编写一个SortedSet
描述整数范围的实现然后使用来制作一个在 O(m) 中运行的版本Set::addAll
,因为TreeSet
的实现包含SortedSet
在线性时间内添加其他 s 的特殊情况。该特殊集合实现的代码非常简单,但涉及大量样板,因此我将其作为练习留给读者!