今天蹲坑的时候看到一个面试题RangeList,实现一个类可以add,remove任意区间,交叉的区间会何必在一起,测试用例如下
const rl = new RangeList();
rl.add([1, 5]);
rl.print();// Should display: [1, 5)
rl.add([10, 20]);
rl.print();// Should display: [1, 5) [10, 20)
rl.add([20, 20]);
rl.print();// Should display: [1, 5) [10, 20)
花了一个小时,整理了一下我的想法:
需要枚举的情况就是要加入或者移除的start和end在已有的range的关系,大致可分为四种
- start在A区间内,end在B区间内,A和B相差N个区间
- start在A区间内,end在B和C的区间断层处,A和C相差N个区间
- start在B和C的区间断层处,end在D区间内,B和D相差N个区间
- start在B和C的区间断层处,end在D和E区间断层处,B和E相差N个区间 其中N是大于等于0的自然数 针对以上四种情况,分别在add和remove写出对应的解法即可(但想写出可令人维护的直观代码并不容易) 这里可以很好的利用splice的原生方法来做对应匹配区间range的替换 下面给出一个自己的写法,只实现了add方法的第二种情况和remove方法的第一种情况
class RangeList {
ranges = [
[1, 5],
[7, 10],
[15, 89],
[100, 105],
];
constructor() {}
_whichRange(num) {
for (let index = 0; index < this.ranges.length; index++) {
const [start, end] = this.ranges[index];
if (num < start) {
return [index - 1, index];
}
if (num >= start && num < end) {
return index;
}
}
return [this.ranges.length - 1];
}
_isInRange(judge) {
return typeof judge === "number";
}
_isOutRange(judge) {
if (Array.isArray(judge)) {
return true;
}
}
_replaceRange(range, start, len) {
this.ranges.splice(start, len - start, range);
}
add(range) {
if (!Array.isArray(range) || range.length !== 2) return;
const [start, end] = range;
const rangeStartIndex = this._whichRange(start);
const rangeEndIndex = this._whichRange(end);
if (this._isInRange(rangeStartIndex)) {
// start命中range任意区间,end在区间断层,隔了N个区间
if (this._isOutRange(rangeEndIndex)) {
const _add = [this.ranges[rangeStartIndex][0], end];
if (rangeEndIndex.length === 1) {
this._replaceRange(
_add,
rangeStartIndex,
this.ranges.length - rangeStartIndex
);
} else {
const [_, _eIndex] = rangeEndIndex;
this._replaceRange(
_add,
rangeStartIndex,
_eIndex - rangeStartIndex
);
}
return;
}
// start命中range任意区间,end区间内,隔了N个区间
if (this._isInRange(rangeEndIndex)) {
return;
}
}
if (this._isOutRange(rangeStartIndex)) {
// start在区间断层处,end在断层内,隔了N个区间
if (this._isOutRange(rangeEndIndex)) {
return;
}
// start在区间断层处,end区间内,隔了N个区间
if (this._isInRange(rangeEndIndex)) {
return;
}
}
}
remove(range) {
if (!Array.isArray(range) || range.length !== 2) return;
const [start, end] = range;
const rangeStartIndex = this._whichRange(start);
const rangeEndIndex = this._whichRange(end);
if (this._isInRange(rangeStartIndex)) {
if (this._isInRange(rangeEndIndex)) {
const [rangeStart] = this.ranges[rangeStartIndex];
const [_, rangeEnd] = this.ranges[rangeEndIndex];
this.ranges.splice(
rangeStartIndex,
rangeEndIndex + 1,
[rangeStart, start],
[end, rangeEnd]
);
return;
}
if (this._isOutRange(rangeEndIndex)) {
return;
}
}
}
print() {
return this.ranges;
}
}
const range = new RangeList();
range.add([4, 96]);
console.log(range.print()); // [ [ 1, 96 ], [ 100, 105 ] ]
range.remove([10, 56]);
console.log(range.print()); // [ [ 1, 10 ], [ 56, 96 ], [ 100, 105 ] ]
range.add([4, 106]);
console.log(range.print()); // [ [ 1, 106 ] ]