区间的合并

区间合并的说明

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

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

完整代码

区间类

java 复制代码
/**
 * 区间类(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 ? "]" : ")");
    }
}

区间合并类

java 复制代码
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;
    }
}

测试代码

java 复制代码
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]]
相关推荐
Escalating_xu4 分钟前
【C++ STL简介】从六大组件到容器、迭代器与算法协作
java·c++·算法
何以解忧,唯有..14 分钟前
Python os模块详解:文件与目录操作指南
java·服务器·python
Csxyzj26 分钟前
kubernetes集群部署方法
java·linux·kubernetes
SQL-First布道者32 分钟前
全面解构传统持久层框架,拥抱真正的 SQL-First
java·数据库·spring boot·sql·spring·mybatis·spring jdbc
小蒜学长1 小时前
vue旅游攻略网站(代码+数据库+LW)
java·数据库·vue.js·spring boot·后端·旅游
凤山老林1 小时前
轻量级规则引擎落地:Spring Boot 集成 LiteFlow 实现动态业务编排与热更新
java·spring boot·后端·规则引擎·liteflow
夏贰四1 小时前
管控数据加载调度如何规避任务冲突?数据加载运维监控体系该如何搭建?
java·大数据·运维
山甫aa2 小时前
JavaWeb后端开发学习手册
java·开发语言·数据库·学习·mysql·springboot·web
鱼鳞_2 小时前
热门八股-JVM
java·jvm
ly76892 小时前
XML 从入门到实践:语法、命名空间、XPath、XSD 与 Java 安全解析
xml·java·python