求一组线段的覆盖范围

package arithmetic;
import java.util.*;

/*
 * 		定义线段类 left 左座标  right 右座标
 * */
class Line
{
	int left;
	int right;
	public Line()
	{}
	public Line(int left,int right)
	{
		this.left = left;
		this.right = right;
	}
}
public class LineOver {
	
	public static void main(String args[])
	{
		long begin=System.currentTimeMillis();
		over();
		System.out.println("over cost: "+runTime(begin));
		begin = System.currentTimeMillis();
		bigOver();
		System.out.println("bigOver cost: "+runTime(begin));
	}
	
	/*
	 * 		用线段覆盖的方法:
	 * 			建立一个 数据 a[min - max-1]  min 表示所有点的最小的座标,max 表示最大 的座标 ,初始值设置为0 a[i] 的值表示是的i -i+1 点的距离
	 * 			对于所有线段遍历,如果线段上段 在数组上,那么数组上的值就设置为1 ,这样所有1 组成的线段就是上面所有线段覆盖的总长度
	 * 
	 * 
	 * 			此方法的时间复杂度决定于下标范围的平方。
				当下标范围很大时([0,10000]),此方法效率太低。

	 * */
	public static void over()
	{
		Line line[] = {new Line(10000,22000),new Line(30300,55000),new Line(44000,60000),new Line(5500000,6000000)};
		int min=line[0].left,max=line[0].right;
		for(int i                                                                                              =1;i<line.length;i++)   //求出线段的最小端点和最大端点
		{
			min = Math.min(min,line[i].left);
			max = Math.max(max,line[i].right);
		}
	
		/*
		 * 		找到最大值时,下面建立数组
		 * */
		int a [] = new int [max];		//以最大端点和最小端点为数组创建一个数组,而座标的范围是 [min-max]
										//注意这个数组表示的意义:每一个元素 a[i] 表示 i -i +1 的范围		//将数组的初始值为0,如果线段覆盖的话,再将其值设置为1				
		for(int i =0;i<line.length;i++)//下面遍历所有线段
			for(int j=line[i].left;j<line[i].right;j++)				//如果一个线段的范围是 [2-4] 那么对应的数组里面的 a[2] a[3] 的值都将会是1(注意:a[4]的值仍然为0,因为a[4]表示的是[4-5]的线段)
				a[j]=1;
		int sum=0;
		for(int i =0;i<max;i++) //这样再统计数组内1的个数,那个所有线段覆盖的范围就可以求出来了 
			if(a[i]==1)
				sum+=1;
		
		System.out.println(sum);
		
		/*
		 * 			该方法就是利用一个数组作为一个线段,把要求的线段都贴到数组线段上去,然后求得被覆盖的线段的总长度即可,
		 * 			然后上面的方法只适用于比较小的数据,而数据较大时,那么就要创建一个一样大的数组,并且这种方法的效率大低
		 * 
		 * */
		
	}
	

	
	/*
	 * 			先说一下原理
	 * 					1. 求出所有线段的端点,再将端点进行一次排序10000,22000,30300 44000 55000 60000
	 * 
	 * 					2. 对所有的线段进行缩放,比如[10000,22000],它的两个端点分别是上面 上面端点的第一个和第二个,那么就可以表示成 [1-2]
	 * 						同理,将所有的端点都这样表示,即,把问题又回到了上面一个,然后再用同样的方法解决
	 * 					3. 	创建一个数组,两样初始值都是0,对于 a[i]  表示 i - i+1 的线段,
	 * 					4.  对数组内所有值为1的进行还原,注意:这时a [i] 中i 对应用的和上面进行排序的数组是一个的,对a [0] 就表示 10000-22000
	 * 						那么即可以求出所以线段的覆盖范围
	 * 
	 * 
	 * 					此方法的时间复杂度决定于线段数的平方。
						对于线段数较多的情况此方法效率太低。
	 * 
	 * */
	
	public static void bigOver()
	{
		Line line[] = {new Line(10000,22000),new Line(30300,55000),new Line(44000,60000),new Line(5500000,6000000)};
		ArrayList<Integer> list = new ArrayList<Integer>();
		for(int i=0;i<line.length;i++)
		{
			if(!list.contains(line[i].left))
				list.add(line[i].left);
			if(!list.contains(line[i].right))
				list.add(line[i].right);
		}
		Collections.sort(list);				//将所有的端点求出并对其进行排序
		//重新构造线段 
		int a [] = new int[list.size()];// Java 中数组的初始值为0 ,所以不要再为其 赋值0
		for(int i=0;i<line.length;i++)
		{
			int left=list.indexOf(line[i].left);// 找出其端点,然后再在对应的 a [] 数组中设置相应的0 or 1 
			int right = list.indexOf(line[i].right);
			for(int j = left;j<right;j++)
				a[j]=1;
		
		}
		int sum=0;
		for(int i =0 ;i<a.length;i++)
				if(a[i]==1)
					sum+=(list.get(i+1)-list.get(i));//注意:此时的a 数组是和 list 对应的,a [1] 就是表示 list.get(2)-list.get(1),这样很重要 
		System.out.println(sum);
	}
	
	
	public static long   runTime(long begin)
	{
		return System.currentTimeMillis()-begin;
	}
	
	

}



 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值