算法 - 查找循环世界中重叠间隔的持续时间(24 小时)
Algorithms - Find duration of overlapping intervals in a cyclic world (24 hours)
我一直在尝试找出用于查找两个时间范围之间的重叠小时数的算法,例如:
应该return12.
和
应该return4.
所以请帮我填补创建以下函数的空白:
public static Long findOverlappingInterval(Long startTime1, Long endTime1,
Long startTime2, Long endTime2){
// Any suggestions?
}
谢谢。
编辑:
我知道创建两个二进制数组的解决方案,使用 AND
并对结果求和。
含义:
但这对我的特定需求没有帮助,因为我想将算法的思想用于 solr 查询,因此 使用数组和二元运算符对我来说不是一个选择 .
/** Start times must be smaller than end times */
public static int findOverlappingInterval(int startTime1, int endTime1, int startTime2, int endTime2) {
int overlappingTime = 0;
int[] time1 = new int[Math.abs(endTime1 - startTime1)];
for (int i1 = startTime1; i1 < endTime1; i1++) {
time1[i1 - startTime1] = i1;
}
int[] time2 = new int[Math.abs(endTime2 - startTime2)];
for (int i2 = startTime2; i2 < endTime2; i2++) {
time2[i2 - startTime2] = i2;
}
for (int i = 0; i < time1.length; i++) {
for (int j = 0; j < time2.length; j++) {
if (time1[i] == time2[j]) {
overlappingTime++;
}
}
}
return overlappingTime;
}
此方法应该适用于您希望它执行的操作。它对我有用。
不过我不确定包装部分。
编辑
/** Returns the overlap between the four time variables */
public static int findOverlappingInterval(int startTime1, int endTime1, int startTime2, int endTime2) {
int overlappingTime = 0;
// First time
int time1Length = 0;
if (endTime1 < startTime1) {
time1Length = 24 - startTime1;
time1Length += endTime1;
}
int[] time1;
if (time1Length == 0) {
time1 = new int[Math.abs(endTime1 - startTime1)];
for (int i1 = startTime1; i1 < endTime1; i1++) {
time1[i1 - startTime1] = i1;
}
} else {
time1 = new int[time1Length];
int count = 0;
for (int i1 = 0; i1 < endTime1; i1++) {
time1[count] = i1;
count++;
}
for (int i1 = startTime1; i1 < 24; i1++) {
time1[count] = i1;
count++;
}
}
// Second time
int time2Length = 0;
if (endTime2 < startTime2) {
time2Length = 24 - startTime2;
time2Length += endTime2;
}
int[] time2;
if (time2Length == 0) {
time2 = new int[Math.abs(endTime2 - startTime2)];
for (int i2 = startTime2; i2 < endTime2; i2++) {
time2[i2 - startTime2] = i2;
}
} else {
time2 = new int[time2Length];
int count = 0;
for (int i2 = 0; i2 < endTime2; i2++) {
time2[count] = i2;
count++;
}
for (int i2 = startTime2; i2 < 24; i2++) {
time2[count] = i2;
count++;
}
}
// Overlap calculator
for (int i = 0; i < time1.length; i++) {
for (int j = 0; j < time2.length; j++) {
if (time1[i] == time2[j]) {
overlappingTime++;
}
}
}
return overlappingTime;
}
这个新代码应该可以满足您的需求。它以 24 小时为周期循环。
首先,对于区间(a, b)
which (a > b)
,我们可以很容易的把它分成两个区间
(a , 23) and (0, b)
所以,问题变成了找到 (a , b)
和 (a1, b1)
与 a <= b and a1 <= b1
之间的重叠
所以,有四种情况:
b < a1
或 b1 < a
,表示没有重叠, return 0
a <= a1 && b1 <= b
,即(a, b)
包含(a1, b1)
,return b1 - a1 + 1
a1 <= a && b <= b1
,即(a1, b1)
包含(a, b)
,return b - a + 1
- 最后一种情况是
(a, b)
和(a1, b1)
每个区间的重叠部分,即重叠区间是(max(a1, a), min(b, b1))
不用创建数组也可以做到,只计算区间之间的交集。一共有三种情况:
- 没有拆分间隔。
- 一个分割间隔。
- 两个间隔分开。
您可以将拆分间隔问题解决为两个单独的间隔。使用递归你可以很容易地做到这一点:
public static Long findOverlappingInterval(Long startTime1, Long endTime1, Long startTime2, Long endTime2)
{
if (startTime1 < endTime1 && startTime2 < endTime2)
return Math.max(0, Math.min(endTime2, endTime1) - Math.max(startTime1, startTime2) + 1);
else
{
if (startTime1 < endTime1)
return findOverlappingInterval(startTime1, endTime1, 0L, endTime2) +
findOverlappingInterval(startTime1, endTime1, startTime2, 23L);
else if (startTime2 < endTime2)
return findOverlappingInterval(0L, endTime1, startTime2, endTime2) +
findOverlappingInterval(startTime1, 23L, startTime2, endTime2);
else
{
return findOverlappingInterval(0L, endTime1, 0L, endTime2) +
findOverlappingInterval(0L, endTime1, startTime2, 23L) +
findOverlappingInterval(startTime1, 23L, 0L, endTime2) +
findOverlappingInterval(startTime1, 23L, startTime2, 23L);
}
}
}
在此处检查 link:Ideone link</code></p>
<blockquote>
<p><sub>EDIT: Inserted the code from the link here:</sub></p>
</blockquote>
<pre><code>import java.util.*;
import java.lang.*;
import java.io.*;
/* Name of the class has to be "Main" only if the class is public. */
class Ideone
{
public static Long min(Long a,Long b){
return ((a)<(b)?(a):(b));
}
public static Long max(Long a,Long b){
return ((a)>(b)?(a):(b));
}
public static void main (String[] args) throws java.lang.Exception
{
Long s1=6L,e1=23L,s2=2L,e2=17L,ans=0L;
Boolean broken1,broken2;
broken1=(s1<=e1)?false:true;
broken2=(s2<=e2)?false:true;
if(broken1){
if(broken2)
ans=min(e1,e2)+1 + 23-max(s1,s2)+1;
else{
if(e1>=s2) ans+=(min(e1,e2)-s2+1);
if(s1<=e2) ans+=(e2-max(s1,s2)+1);
}
}
else{
if(broken2){
if(e2>=s1) ans+=(min(e1,e2)-s1+1);
if(s2<=e1) ans+=(e1-max(s1,s2)+1);
}
else{
if(e1<s2 || e2<s1) ans=0L;
else ans=min(e1,e2)-max(s1,s2)+1;
}
}
System.out.println(ans+"");
}
}
令人惊讶的是,短时间内得到了很多答案...
我遵循了其他答案中已经提出的相同想法:当开始时间 s
小于结束时间 e
时,结果可以分解为两个单独的计算,对于范围 [s,24]
和 [0,e]
.
这个可以做到"mutually"所以只考虑3个简单的情况,剩下的可以用递归调用来完成。
不过,我试过了
- 考虑到(根据图像)终点应该包含 (!)
- 再添加一些测试用例
- 很好地可视化配置:-)
这是 MCVE:
的结果
public class OverlappingIntervals
{
private static final long INTERVAL_SIZE = 24;
public static void main(String[] args)
{
test(6,23, 2,17);
test(0,12, 12,2);
test(11,4, 12,3);
test(12,4, 11,3);
}
private static void test(
long s0, long e0, long s1, long e1)
{
System.out.println(createString(s0, e0, s1, e1));
System.out.println(findOverlappingInterval(s0, e0, s1, e1));
}
private static String createString(
long s0, long e0, long s1, long e1)
{
StringBuilder sb = new StringBuilder();
sb.append(createString(s0, e0, "A")).append("\n");
sb.append(createString(s1, e1, "B"));
return sb.toString();
}
private static String createString(long s, long e, String c)
{
StringBuilder sb = new StringBuilder();
for (int i=0; i<INTERVAL_SIZE; i++)
{
if (s < e)
{
if (i >= s && i <= e)
{
sb.append(c);
}
else
{
sb.append(".");
}
}
else
{
if (i <= e || i >= s)
{
sb.append(c);
}
else
{
sb.append(".");
}
}
}
return sb.toString();
}
public static long findOverlappingInterval(
long s0, long e0, long s1, long e1)
{
return compute(s0, e0+1, s1, e1+1);
}
public static long compute(
long s0, long e0, long s1, long e1)
{
if (s0 > e0)
{
return
compute(s0, INTERVAL_SIZE, s1, e1) +
compute(0, e0, s1, e1);
}
if (s1 > e1)
{
return
compute(s0, e0, s1, INTERVAL_SIZE) +
compute(s0, e0, 0, e1);
}
return Math.max(0, Math.min(e0, e1) - Math.max(s0, s1));
}
}
前两个测试用例是问题中给出的测试用例,它们分别正确打印12
和4
。其余两个用于测试其他重叠配置:
......AAAAAAAAAAAAAAAAAA
..BBBBBBBBBBBBBBBB......
12
AAAAAAAAAAAAA...........
BBB.........BBBBBBBBBBBB
4
AAAAA......AAAAAAAAAAAAA
BBBB........BBBBBBBBBBBB
16
AAAAA.......AAAAAAAAAAAA
BBBB.......BBBBBBBBBBBBB
16
但是,请注意,可能必须创建进一步的测试配置才能涵盖所有可能的情况。
我一直在尝试找出用于查找两个时间范围之间的重叠小时数的算法,例如:
应该return12.
和
应该return4.
所以请帮我填补创建以下函数的空白:
public static Long findOverlappingInterval(Long startTime1, Long endTime1,
Long startTime2, Long endTime2){
// Any suggestions?
}
谢谢。
编辑:
我知道创建两个二进制数组的解决方案,使用 AND
并对结果求和。
含义:
但这对我的特定需求没有帮助,因为我想将算法的思想用于 solr 查询,因此 使用数组和二元运算符对我来说不是一个选择 .
/** Start times must be smaller than end times */
public static int findOverlappingInterval(int startTime1, int endTime1, int startTime2, int endTime2) {
int overlappingTime = 0;
int[] time1 = new int[Math.abs(endTime1 - startTime1)];
for (int i1 = startTime1; i1 < endTime1; i1++) {
time1[i1 - startTime1] = i1;
}
int[] time2 = new int[Math.abs(endTime2 - startTime2)];
for (int i2 = startTime2; i2 < endTime2; i2++) {
time2[i2 - startTime2] = i2;
}
for (int i = 0; i < time1.length; i++) {
for (int j = 0; j < time2.length; j++) {
if (time1[i] == time2[j]) {
overlappingTime++;
}
}
}
return overlappingTime;
}
此方法应该适用于您希望它执行的操作。它对我有用。 不过我不确定包装部分。
编辑
/** Returns the overlap between the four time variables */
public static int findOverlappingInterval(int startTime1, int endTime1, int startTime2, int endTime2) {
int overlappingTime = 0;
// First time
int time1Length = 0;
if (endTime1 < startTime1) {
time1Length = 24 - startTime1;
time1Length += endTime1;
}
int[] time1;
if (time1Length == 0) {
time1 = new int[Math.abs(endTime1 - startTime1)];
for (int i1 = startTime1; i1 < endTime1; i1++) {
time1[i1 - startTime1] = i1;
}
} else {
time1 = new int[time1Length];
int count = 0;
for (int i1 = 0; i1 < endTime1; i1++) {
time1[count] = i1;
count++;
}
for (int i1 = startTime1; i1 < 24; i1++) {
time1[count] = i1;
count++;
}
}
// Second time
int time2Length = 0;
if (endTime2 < startTime2) {
time2Length = 24 - startTime2;
time2Length += endTime2;
}
int[] time2;
if (time2Length == 0) {
time2 = new int[Math.abs(endTime2 - startTime2)];
for (int i2 = startTime2; i2 < endTime2; i2++) {
time2[i2 - startTime2] = i2;
}
} else {
time2 = new int[time2Length];
int count = 0;
for (int i2 = 0; i2 < endTime2; i2++) {
time2[count] = i2;
count++;
}
for (int i2 = startTime2; i2 < 24; i2++) {
time2[count] = i2;
count++;
}
}
// Overlap calculator
for (int i = 0; i < time1.length; i++) {
for (int j = 0; j < time2.length; j++) {
if (time1[i] == time2[j]) {
overlappingTime++;
}
}
}
return overlappingTime;
}
这个新代码应该可以满足您的需求。它以 24 小时为周期循环。
首先,对于区间(a, b)
which (a > b)
,我们可以很容易的把它分成两个区间
(a , 23) and (0, b)
所以,问题变成了找到 (a , b)
和 (a1, b1)
与 a <= b and a1 <= b1
所以,有四种情况:
b < a1
或b1 < a
,表示没有重叠, return 0a <= a1 && b1 <= b
,即(a, b)
包含(a1, b1)
,returnb1 - a1 + 1
a1 <= a && b <= b1
,即(a1, b1)
包含(a, b)
,returnb - a + 1
- 最后一种情况是
(a, b)
和(a1, b1)
每个区间的重叠部分,即重叠区间是(max(a1, a), min(b, b1))
不用创建数组也可以做到,只计算区间之间的交集。一共有三种情况:
- 没有拆分间隔。
- 一个分割间隔。
- 两个间隔分开。
您可以将拆分间隔问题解决为两个单独的间隔。使用递归你可以很容易地做到这一点:
public static Long findOverlappingInterval(Long startTime1, Long endTime1, Long startTime2, Long endTime2)
{
if (startTime1 < endTime1 && startTime2 < endTime2)
return Math.max(0, Math.min(endTime2, endTime1) - Math.max(startTime1, startTime2) + 1);
else
{
if (startTime1 < endTime1)
return findOverlappingInterval(startTime1, endTime1, 0L, endTime2) +
findOverlappingInterval(startTime1, endTime1, startTime2, 23L);
else if (startTime2 < endTime2)
return findOverlappingInterval(0L, endTime1, startTime2, endTime2) +
findOverlappingInterval(startTime1, 23L, startTime2, endTime2);
else
{
return findOverlappingInterval(0L, endTime1, 0L, endTime2) +
findOverlappingInterval(0L, endTime1, startTime2, 23L) +
findOverlappingInterval(startTime1, 23L, 0L, endTime2) +
findOverlappingInterval(startTime1, 23L, startTime2, 23L);
}
}
}
在此处检查 link:Ideone link</code></p>
<blockquote>
<p><sub>EDIT: Inserted the code from the link here:</sub></p>
</blockquote>
<pre><code>import java.util.*;
import java.lang.*;
import java.io.*;
/* Name of the class has to be "Main" only if the class is public. */
class Ideone
{
public static Long min(Long a,Long b){
return ((a)<(b)?(a):(b));
}
public static Long max(Long a,Long b){
return ((a)>(b)?(a):(b));
}
public static void main (String[] args) throws java.lang.Exception
{
Long s1=6L,e1=23L,s2=2L,e2=17L,ans=0L;
Boolean broken1,broken2;
broken1=(s1<=e1)?false:true;
broken2=(s2<=e2)?false:true;
if(broken1){
if(broken2)
ans=min(e1,e2)+1 + 23-max(s1,s2)+1;
else{
if(e1>=s2) ans+=(min(e1,e2)-s2+1);
if(s1<=e2) ans+=(e2-max(s1,s2)+1);
}
}
else{
if(broken2){
if(e2>=s1) ans+=(min(e1,e2)-s1+1);
if(s2<=e1) ans+=(e1-max(s1,s2)+1);
}
else{
if(e1<s2 || e2<s1) ans=0L;
else ans=min(e1,e2)-max(s1,s2)+1;
}
}
System.out.println(ans+"");
}
}
令人惊讶的是,短时间内得到了很多答案...
我遵循了其他答案中已经提出的相同想法:当开始时间 s
小于结束时间 e
时,结果可以分解为两个单独的计算,对于范围 [s,24]
和 [0,e]
.
这个可以做到"mutually"所以只考虑3个简单的情况,剩下的可以用递归调用来完成。
不过,我试过了
- 考虑到(根据图像)终点应该包含 (!)
- 再添加一些测试用例
- 很好地可视化配置:-)
这是 MCVE:
的结果public class OverlappingIntervals
{
private static final long INTERVAL_SIZE = 24;
public static void main(String[] args)
{
test(6,23, 2,17);
test(0,12, 12,2);
test(11,4, 12,3);
test(12,4, 11,3);
}
private static void test(
long s0, long e0, long s1, long e1)
{
System.out.println(createString(s0, e0, s1, e1));
System.out.println(findOverlappingInterval(s0, e0, s1, e1));
}
private static String createString(
long s0, long e0, long s1, long e1)
{
StringBuilder sb = new StringBuilder();
sb.append(createString(s0, e0, "A")).append("\n");
sb.append(createString(s1, e1, "B"));
return sb.toString();
}
private static String createString(long s, long e, String c)
{
StringBuilder sb = new StringBuilder();
for (int i=0; i<INTERVAL_SIZE; i++)
{
if (s < e)
{
if (i >= s && i <= e)
{
sb.append(c);
}
else
{
sb.append(".");
}
}
else
{
if (i <= e || i >= s)
{
sb.append(c);
}
else
{
sb.append(".");
}
}
}
return sb.toString();
}
public static long findOverlappingInterval(
long s0, long e0, long s1, long e1)
{
return compute(s0, e0+1, s1, e1+1);
}
public static long compute(
long s0, long e0, long s1, long e1)
{
if (s0 > e0)
{
return
compute(s0, INTERVAL_SIZE, s1, e1) +
compute(0, e0, s1, e1);
}
if (s1 > e1)
{
return
compute(s0, e0, s1, INTERVAL_SIZE) +
compute(s0, e0, 0, e1);
}
return Math.max(0, Math.min(e0, e1) - Math.max(s0, s1));
}
}
前两个测试用例是问题中给出的测试用例,它们分别正确打印12
和4
。其余两个用于测试其他重叠配置:
......AAAAAAAAAAAAAAAAAA
..BBBBBBBBBBBBBBBB......
12
AAAAAAAAAAAAA...........
BBB.........BBBBBBBBBBBB
4
AAAAA......AAAAAAAAAAAAA
BBBB........BBBBBBBBBBBB
16
AAAAA.......AAAAAAAAAAAA
BBBB.......BBBBBBBBBBBBB
16
但是,请注意,可能必须创建进一步的测试配置才能涵盖所有可能的情况。