部分文章内容为公开资料查询整理,原文出处可能未标注,如有侵权,请联系我,谢谢。邮箱地址:gnivor@163.com ►►►需要气球么?请点击我吧!

编程之美--2.19区间重合判断

问题:给定一个源区间[x,y] (y>=x)和N个无序目标区间[x1,y1][x2,y2][x3,y3]...[xn,yn],判断[x,y]是否在目标区间内。

解法1:

将所有的小区间映射到数轴上。inter[]数组代表数轴。(在这里假定所有的区间都在正半轴)

例如:如果arr[0]=1 arr[1] = 5, 那么inter[0,1,2,3,4]=1; 这样可以判断数轴上被映射的区间是否能包含给定区间。

代码:

 

//解法1 : 将所有小区间映射到数轴上,时间复杂度为O(N^2)
public static boolean IsCoincide1(int[] arr , int start , int end){
    int len = arr.length;
    //找到最大的值
    int maxa = arr[0];
    for(int i= 1 ; i < len ; i++){
        if(arr[i]>maxa)
            maxa = arr[i] ;            
    }        
    if(end > maxa ) //如果区间终点比数组内所有最大值还大,则肯定不包含在数组之内
        return false;        
    int[] inter = new int[maxa];     //代表数轴
    
    //将区间画在数轴上
    for(int i = 0 ; i < len ; i+=2){
        int a = arr[i];     //当前区间的起点
        int b = arr[i+1];    //当前区间的终点
        System.out.print(a+" "+b+" ");
        for(int j = a ; j < b ; j++){ 
            //注意,这里是小于,不是小于等于
            //inter[2]=1代表[2,3]被填充。
            inter[j]=1;
        }
    }
    
    //输出数轴情况
    System.out.print("\n数轴为:");
    for(int i = 1 ; i < maxa ; i++){
        System.out.print(inter[i]+" ");
    }
    System.out.println();
    
    //判断区间是否落在组合区间内
    //注意,这里也是小于,原因同上
    for(int i = start ; i <end ; i++){
        if(inter[i]==0)
            return false;
    }
    return true;
}

 

main函数内的代码:

int[] arr = {2,3,1,2,3,9};
System.out.println("大小区间是否重合:"+IsCoincide1(arr,1,6)+"\n");
int[] arr2 = {2,4,1,3,5,9};
System.out.println("大小区间是否重合:"+IsCoincide1(arr2,1,6)+"\n");        

输出结果:

 

2 3 1 2 3 9 
数轴为:1 1 1 1 1 1 1 1 
大小区间是否重合:true

2 4 1 3 5 9 
数轴为:1 1 1 0 1 1 1 1 
大小区间是否重合:false

 

 

解法2:

先将所有小的区间排序、然后处理。排序采用快排,对所有小区间的起始点进行排序。
注意,本算法没考虑这种情况:一个小区间包含在另一个小区间之内:[1,4] [2,3]

代码: 

//解法2:将所有小区间排序、合并
public static boolean IsCoincide2(int[] arr,int start , int end){
    MyQuickSort(arr,0,arr.length-2);
    for(int i = 0 ; i < arr.length ; i++){
        System.out.print(arr[i]+" ");
    }
    int tstart =0;
    int tend = 0;
    if (arr[tstart]<=start){
        tend = 1;
        while(arr[tend]<end){
            if(arr[tend]>=arr[tend+1]) //如果后一个小区间的起点值<=前一个区间的终点,说明两个区间有重合
                tend+=2;
            else break;
        }
        if(arr[tend]>=end)
            return true;
        else return false;
    }
    return false;
}

//快排·改,根据区间起始点进行排序
public static void MyQuickSort(int[] a,int left,int right){
    if(left>right)
        return;
    int key = a[left];    //设定最左边的元素为key
    int key_r = a[left+1]; //保存key右侧的那个数
    int low = left;
    int high = right;
    while(low<high){
        while(low<high && a[high]>key)    
            high-=2;
        a[low]=a[high];
        a[low+1] = a[high+1];
        while(low<high && a[low]<key)
            low+=2;
        a[high]=a[low];
        a[high+1] = a[low+1];
    }
    a[low]=key;//将Key最终放在这个位置,左边的元素均比key小,右边的元素均比key大
    a[low+1] = key_r;     //将key右侧的数归位
    MyQuickSort(a, left, low-2);
    MyQuickSort(a, low+3, right);
}

 main函数内代码:

int[] arr = {2,3,1,2,3,9};
int[] arr2 = {2,4,1,3,5,9};
System.out.println(IsCoincide2(arr,1,6));
System.out.println(IsCoincide2(arr2,1,6));

运行结果:

1 2 2 3 3 9 true
1 3 2 4 5 9 false

 

解法2改:

先将数组排序,然后进行合并,最后处理。排序采用快排,对所有小区间的起始点进行排序。

实际上加了一个合并区间的函数

//解法2:将所有小区间排序、合并
public static boolean IsCoincide2(int[] arr,int start , int end){
    MyQuickSort(arr,0,arr.length-2);
    System.out.print("排好序的小区间为:");
    for(int i = 0 ; i < arr.length ; i++){
        System.out.print(arr[i]+" ");
    }
    System.out.print("\n合并后的区间为:");
    arr = MyMerge(arr); //注意,值传递和引用传递区别,如果在main输出arr,仍然是排好序的,而不是合并后的
    for(int i = 0 ; i < arr.length ; i++){
        System.out.print(arr[i]+" ");
    }
    
    int tstart =0;
    int tend = 0;
    if (arr[tstart]<=start){
        tend = 1;
        while(arr[tend]<end){
            if(arr[tend]>=arr[tend+1]) //如果后一个小区间的起点值<=前一个区间的终点,说明两个区间有重合
                tend+=2;
            else break;
        }
        if(arr[tend]>=end)
            return true;
        else return false;
    }
    return false;
}

//快排·改,根据区间起始点进行排序
public static void MyQuickSort(int[] a,int left,int right){
    if(left>right)
        return;
    int key = a[left];    //设定最左边的元素为key
    int key_r = a[left+1]; //保存key右侧的那个数
    int low = left;
    int high = right;
    while(low<high){
        while(low<high && a[high]>key)    
            high-=2;
        a[low]=a[high];
        a[low+1] = a[high+1];
        while(low<high && a[low]<key)
            low+=2;
        a[high]=a[low];
        a[high+1] = a[low+1];
    }
    a[low]=key;//将Key最终放在这个位置,左边的元素均比key小,右边的元素均比key大
    a[low+1] = key_r;     //将key右侧的数归位
    MyQuickSort(a, left, low-2);
    MyQuickSort(a, low+3, right);
}

//将已经按顺序排列的小区间合并
public static int[] MyMerge(int[] arr){
    int len = arr.length;
    int[] b = new int[len];
    b[0]=arr[0]; b[1]= arr[1];
    int k = 1 ;    
    int b_len = 2;
    for(int i =  2 ; i < len ; i+=2){
        if(b[k] >= arr[i]){
            b[k] = Math.max(arr[i-1], arr[i+1]);
        }else{
            k+=2;
            b_len +=2;
            b[k-1] = arr[i];
            b[k] = arr[i+1];
        }
    }
    int[] merge_arr = new int[b_len];
    for(int i = 0 ; i < b_len ; i++)
        merge_arr[i]=b[i];
    return merge_arr;        
}

main()函数的代码

//int[] arr2 = {1,4,2,3,4,9}; //这种情况在没有merge的解法二中判断不出来,改版后可以
System.out.println("\n大小区间是否重合:"+IsCoincide2(arr,1,6)+"\n");        
System.out.println("\n大小区间是否重合:"+IsCoincide2(arr2,1,6)+"\n");

输出结果:

排好序的小区间为:1 2 2 3 3 9 
合并后的区间为:1 9 
大小区间是否重合:true

排好序的小区间为:1 3 2 4 5 9 
合并后的区间为:1 4 5 9 
大小区间是否重合:false

 

posted @ 2015-06-23 11:17  流了个火  阅读(219)  评论(0)    收藏  举报
►►►需要气球么?请点击我吧!►►►
View My Stats