区间的合并

区间合并的说明

业务中的区间合并是比较常见的需求,区间合并的核心有两点:

  1. 合并前排序,后面处理起来可以简单很多;
  2. 两个区间合并,这是多个区间合并的基础。

完整代码

区间类

/**
 * 区间类(left、right可以根据需要改为BigDecimal或其它类型)
 */
public class Section {
    private int left;
    private boolean isLeftClose;
    private int right;
    private boolean isRightClose;

    public Section(int left, boolean isLeftClose, int right, boolean isRightClose) {
        this.left = left;
        this.isLeftClose = isLeftClose;
        this.right = right;
        this.isRightClose = isRightClose;
        checkParam();
    }

    public Section(int left, int right) {
        this.left = left;
        this.isLeftClose = true;
        this.right = right;
        this.isRightClose = true;
        checkParam();
    }

    private void checkParam() {
        if (left == right && !(isLeftClose && isRightClose)) {
            throw new RuntimeException("If left and right are the same, both sides must be closed intervals");
        }
        if (left > right) {
            throw new RuntimeException("left is greater than the right");
        }
    }

    public int getLeft() {
        return left;
    }

    public void setLeft(int left) {
        this.left = left;
    }

    public boolean isLeftClose() {
        return isLeftClose;
    }

    public void setLeftClose(boolean leftClose) {
        isLeftClose = leftClose;
    }

    public int getRight() {
        return right;
    }

    public void setRight(int right) {
        this.right = right;
    }

    public boolean isRightClose() {
        return isRightClose;
    }

    public void setRightClose(boolean rightClose) {
        isRightClose = rightClose;
    }

    @Override
    public String toString() {
        return (isLeftClose ? "[" : "(") + left + ", " + right + (isRightClose ? "]" : ")");
    }
}

区间合并类

import java.util.ArrayList;
import java.util.List;

/**
 * 区间合并类
 */
public class MergeSection {
    /**
     * 合并区间
     *
     * @param sections 待合并区间
     * @return 合并后的区间
     */
    public List<Section> mergeSections(List<Section> sections) {
        List<Section> merged = new ArrayList<>();
        if (sections == null || sections.size() == 0) {
            return merged;
        }
        sections.sort((o1, o2) -> o1.getLeft() - o2.getLeft());
        merged = doMerge(sections);
        return merged;
    }

    /**
     * 真正合并区间的函数
     * <p>
     * 由于已经排过序,所以新加入的区间只会跟最后一个区间产生关联。
     * 用last表示最后一个区间,section表示新加入的区间。可能有以下几种情况:
     * 1 section.getLeft() < last.getLeft() -->由于排过序了,所以不会出现这种情况
     * 2 section.getLeft() < last.getRight()
     * 2.1 section.getRight() < last.getRight() -->不用处理
     * 2.2 section.getRight() == last.getRight() -->处理开闭区间
     * 2.3 section.getRight() > last.getRight() -->更新last.getRight()
     * 3 section.getLeft() == last.getRight() -->处理开闭区间
     * 4 section.getLeft() > last.getRight() -->添加区间
     *
     * @param sections 待合并区间
     * @return 合并后的区间
     */
    private List<Section> doMerge(List<Section> sections) {
        List<Section> merged = new ArrayList<>();
        if (sections == null || sections.size() == 0) {
            return merged;
        }
        merged.add(sections.get(0));
        for (int index = 1; index < sections.size(); index++) {
            Section section = sections.get(index);
            Section last = merged.get(merged.size() - 1);
            if (section.getLeft() < last.getRight()) {
                if (last.getLeft() == section.getLeft()) {
                    last.setLeftClose(last.isLeftClose() || section.isLeftClose());
                }
                if (section.getRight() == last.getRight()) {
                    last.setRightClose(last.isRightClose() || section.isRightClose());
                } else if (section.getRight() > last.getRight()) {
                    last.setRight(section.getRight());
                    last.setRightClose(section.isRightClose());
                }
            } else if (section.getLeft() == last.getRight()) {
                if (section.isLeftClose() || last.isRightClose()) {
                    last.setRight(section.getRight());
                    last.setRightClose(section.isRightClose());
                } else {
                    merged.add(section);
                }
            } else {
                merged.add(section);
            }
        }
        return merged;
    }
}

测试代码

import java.util.ArrayList;
import java.util.List;

public class Test {
    public static void main(String[] args) {
        List<Section> list = new ArrayList<>();
        list.add(new Section(1, 2));
        list.add(new Section(3, 4));
        list.add(new Section(5, false, 6, false));
        list.add(new Section(6, false, 7, false));
        list.add(new Section(7, true, 8, true));
        list.add(new Section(8, false, 9, false));
        list.add(new Section(10, false, 11, true));
        list.add(new Section(10, true, 11, false));
        list.add(new Section(12, false, 14, false));
        list.add(new Section(12, true, 15, false));
        list.add(new Section(16, true, 18, false));
        list.add(new Section(16, false, 19, true));
        System.out.println(list);
        List<Section> merged = new MergeSection().mergeSections(list);
        System.out.println(merged);
    }
}

运行结果:

[[1, 2], [3, 4], (5, 6), (6, 7), [7, 8], (8, 9), (10, 11], [10, 11), (12, 14), [12, 15), [16, 18), (16, 19]]
[[1, 2], [3, 4], (5, 6), (6, 9), [10, 11], [12, 15), [16, 19]]
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值