编程之美--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

浙公网安备 33010602011771号