Jerry前端面试题编码题-Ranklist

1,314 阅读1分钟

题目

Version:0.9 StartHTML:0000000105 EndHTML:0000007516 StartFragment:0000000141 EndFragment:0000007476

class RangeList {
    add(range) {}

    remove(range) {}

    print() {}
}

// Example run
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)

rl.add([20, 21]);
rl.print();// Should display: [1, 5) [10, 21)

rl.add([2, 4]);
rl.print();// Should display: [1, 5) [10, 21)

rl.add([3, 8]);
rl.print();// Should display: [1, 8) [10, 21)

rl.remove([10, 10]);
rl.print();// Should display: [1, 8) [10, 21)

rl.remove([10, 11]);
rl.print();// Should display: [1, 8) [11, 21)

rl.remove([15, 17]);
rl.print();// Should display: [1, 8) [11, 15) [17, 21)

rl.remove([3, 19]);
rl.print(); // Should display: [1, 3) [19, 21)

答案:

class RangeList {
    constructor() {
        this.list = [];
    }
    reRank(list, i) {
        const [min, max] = list[i];
        let res = [...list];

        // 记录需要更新的位置以及范围
        let start = i;
        let end = i;
        let resMin = min;
        let resMax = max;
        
        // 判断是否与前一个范围重叠
        if (i !== 0) {
            const [preMin, preMax] = list[i - 1];
            if (min <= preMax) {
                // 与前一个范围重合,指针迁移
                start = i - 1;

                // 新的范围 min值调整为前一个范围
                resMin = preMin;
            }
        }

        let index = i + 1;
        while(index < list.length) {
            const [nextMin, nextMax] = list[index];

            // 寻找右侧重复的范围
            if (max >= nextMin && max <= nextMax) {
                end = index;
                resMax = nextMax;
                break;
            }
            else if (max > nextMax){
                end = index + 1;
            }
            index++;
        }
        res.splice(start, end - start + 1, [resMin, resMax]);
        return res;
    }
    add(range) {
        let list = [...this.list];
        let [curMin, curMax] = range;
        const len = list.length;

        // 现有list长度为0时,直接push
        if (len === 0) {
            this.list.push(range);
            return;
        }

        for(var i = 0; i < len; i++) {
            const [min] = list[i];
            if (curMin < min) {

                // 先把范围插入到数组中
                list.splice(i, 0, range);

                // 重新排序
                list = this.reRank(list, i);
                break;
            }
        }

        // 没有插入数组中
        if (list.length === len && list[len - 1][1] < curMin) {
            list.push(range);
        }
        else if (list.length === len && list[len - 1][1] >= curMin) {
            list.splice(len - 1, 1, [list[len - 1][0], Math.max(list[len - 1][1], curMax)]);
        }
        this.list = list;
    }
    remove(range) {
        // 当前需要移除的范围
        let [curMin, curMax] = range;
        let list = [...this.list];

        for(let i = 0, l = list.length; i < l; i++) {
            const [min, max] = this.list[i];
            
            // 移除范围与当前范围有交集
            if (!(curMin > max || curMax < min)) {
                let arr = [];

                // 左边需要移除
                if (curMin <= min && curMax <= max) {
                    if (curMax + 1 !== max) {
                        arr.push([curMax + 1, max])
                    }                    
                }

                // 中间需要移除
                else if (curMin > min && curMax < max){
                    arr.push([min, curMin], [curMax, max]);
                }

                // 右边需要移除
                else {
                    if (min !== curMin) {
                        arr.push([min, curMin])
                    }
                }
                list.splice(i, 1, ...arr);
            } 
        }
        this.list = list;
    }
    print() {
        const list = this.list;
        let res = '';
        for(let item in list) {
            res += `[${list[item].toString()})`
        }
        return res;
    }
}