区间求交集算法
来源:互联网 发布:spss多维数据分析 编辑:程序博客网 时间:2024/05/29 23:24
最近要去网易笔试,做往年笔试题的时候遇到一个比较难搞的,原题:有两个有序的集合,集合的每个元素都是一段范围,求其交集,例如集合{[4,8],[9,13]}和{[6,12]}的交集为{[6,8],[9,12]}
在网上看了一下没有比较巧妙地解决方案,于是自己想了一个,思路如下,我假设了两个区间集合A{[2,4],[8,14],[15,20],[22,25]},B{[1,5],[8,16],[19,25],[30,40]}
将这两个集合表示在图上就是下面这样子的:
我们可以画一条线,这条线是假想的,你可以把这条线想象是一个传感器,它能统计穿过了多少个点,比如下图线就是有一个点穿过了线。
这样我们就能通过穿过线的点的个数来判断是否区间重合了。我们有结论,当穿过线的点多余一个的时候(必须有两个点,一个来自A,一个来自B)那么区间重合,这条线有一个专业名词叫做扫线,这名字很形象。
好的,思路讲完了,直接看代码:
public class SetSort {
//声明两个数组,分别表示集合A,B
ArrayList<Range> ralist = new ArrayList<Range>();
ArrayList<Range> rblist = new ArrayList<Range>();
//这里是初始化一下数据,没啥可说的
public void DataInial() {
Range r1 = new Range();
r1.left = 2;
r1.right = 4;
Range r2 = new Range();
r2.left = 8;
r2.right = 14;
Range r3 = new Range();
r3.left = 15;
r3.right = 20;
Range r4 = new Range();
r4.left = 22;
r4.right = 25;
Range r5 = new Range();
r5.left = 1;
r5.right = 5;
Range r6 = new Range();
r6.left = 8;
r6.right = 16;
Range r7 = new Range();
r7.left = 19;
r7.right = 25;
Range r8 = new Range();
r8.left = 30;
r8.right = 40;
ralist.add(r1);
ralist.add(r2);
ralist.add(r3);
ralist.add(r4);
rblist.add(r5);
rblist.add(r6);
rblist.add(r7);
rblist.add(r8);
}
public static void main(String[] args) {
//交集集合
ArrayList<Range> list = new ArrayList<Range>();
SetSort ss = new SetSort();
ss.DataInial();
list = Help.FindRange(ss.ralist, ss.rblist);
for (Range r : list) {
System.out.println("[" + r.left + "," + r.right + "]");
}
}
}
class Help {
public static ArrayList<Range> FindRange(ArrayList<Range> ra, ArrayList<Range> rb) {
int max = 0;//这个值表示count所要循环的上界
ArrayList<Range> rclist = new ArrayList<Range>();//交集的集合
if (ra.get(ra.size() - 1).right > rb.get(rb.size() - 1).right) {
max = rb.get(rb.size() - 1).right;
} else {
max = ra.get(ra.size() - 1).right;
}
int count = 0;//这个值就是扫线的坐标
if (ra.get(0).left > rb.get(0).left) {
count = ra.get(0).left;
} else {
count = rb.get(0).left;
}
int left = 0;
int right = 0;
boolean flage = false;
//核心算法
for (; count < max+1; count++) {
//如果扫线刚好有两个点穿过,则记载第一次的值,作为区间的左值,当穿过扫线的点由多个变为一个或者0个的时候,
//则记录正要变化的那个count的值作为区间的右值
//这里面的flage用来防止重复赋值给区间
if (IS_ELEMENT(ra, count) && IS_ELEMENT(rb, count)) {
if (!flage) {
left = count;
flage = true;
}
} else {
if (flage) {
right = count;
flage = false;
//new一个区间,添加到交集集合中去
rclist.add(new Range(left, right));
}
}
}
return rclist;
}
//这个方法用来判断,当前扫线的值,是否在集合某个元素中
public static boolean IS_ELEMENT(ArrayList<Range> list, int count) {
boolean flag = false;
for (int i = 0; i < list.size(); i++) {
if (list.get(i).right <= count) {
continue;
}
if (list.get(i).left > count) {
break;
}
if (list.get(i).left <= count && list.get(i).right >= count) {
flag = true;
break;
}
}
return flag;
}
}
//数组中的元素结构
class Range {
public Range() {
}
int right = 0;
int left = 0;
public Range(int left, int right) {
this.right = right;
this.left = left;
}
}
这个算法想了好几个小时,总算是想出来了,其实这个算法有个缺点,就是当集合中的区间比较少,但是区间长度比较大的时候,count会循环很多次,比如A{[2,6],[10,100000]};B{[3,8],[9,100000]}这个区间的交集是[3,6],[10,100000]这意味着count需要循环100000次左右,这是非常浪费的。有兴趣的朋友可以自己试着改进一下我的算法。
- 区间求交集算法
- 算法 n1段区间 与 n2段区间求交集
- 基本算法,求交集
- 求反交集算法
- java字符串求交集算法
- 算法&大数据--(1)求交集
- 求交集
- 求交集
- ZCMU-1772-区间交集
- 基本归并算法(求两个集合的交集)
- 以单链表存储的两个集合求交集的算法
- 最快速度求两个数组之交集算法
- 【算法题集锦之二】--多个集合求交集
- 求交集和并集的线性算法
- 最快速度求两个数组之交集算法
- 最快速度求两个数组之交集算法与hash
- 求交集和并集的线性算法
- 设计一函数,求整数区间[a,b]和[c,d]的交集
- TC SRM 684 Div2
- Android开发工程师面试题总结。android开发面试经验
- ETL系列:开发人员常用oracle的查询语句
- Photoshopcs6安装破解
- spring+shiro+cas的整合问题之循环重定向
- 区间求交集算法
- Activity四大基本状态
- MAC快捷键
- 网络概述
- Beego安装 Mac linux
- Windows + IDEA + SBT 打造Spark源码阅读环境
- 工作站操作系统
- 文章标题
- 测试指南:深刻理解“性能测试”