2016-01-19 87 views
6

我一直在试图找出算法寻找重叠小时两个时间范围之间的数字,例如:算法 - 查找循环世界重叠的间隔(24小时)的时间

enter image description here

应该返回12

而且

enter image description here

应该返回4。

所以,请帮我填的空白创建以下功能:

public static Long findOverlappingInterval(Long startTime1, Long endTime1, 
              Long startTime2, Long endTime2){ 
    // Any suggestions? 
} 

感谢。

编辑: 我知道创建两个二进制数组的解决方案,使用AND并总结结果。 含义:

enter image description here

但不会帮助我的具体需求,因为我想使用该算法的想法为Solr的查询,所以使用数组和二元运算不是我的选项。

+0

在第二个示例中,该间隔是如何破坏的?你会如何在startTime和endTime中表示它? –

+0

@RahulJain'startTime = 12','endTime = 2'。这是一个循环的世界。 – Daniel

+0

我一直在为你发布代码,但StackOverflow一直警告我,缩进不正确 –

回答

3

令人惊讶的是许多ans WERS在很短的时间...

我跟着一个已经在其他的答案提出了同样的想法:当启动时间s比结束时间e较小,那么结果可以分解为两个独立的计算,范围为[s,24][0,e]

这可以“互相”完成,因此只有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)); 
    } 
} 

前两个测试用例是具有的那些已在问题中给出,并分别正确地打印124。剩下的两个被用于测试其他重叠配置:

......AAAAAAAAAAAAAAAAAA 
..BBBBBBBBBBBBBBBB...... 
12 
AAAAAAAAAAAAA........... 
BBB.........BBBBBBBBBBBB 
4 
AAAAA......AAAAAAAAAAAAA 
BBBB........BBBBBBBBBBBB 
16 
AAAAA.......AAAAAAAAAAAA 
BBBB.......BBBBBBBBBBBBB 
16 

然而,请注意,进一步的测试配置可以具有以覆盖所有可能的情况下被创建。

0
/** 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小时。

+0

我不能让'/ **开始时间必须小于结束时间* /'的假设。在第二个例子中'startTime'大于'endTime'。 – Daniel

+0

我已经为它添加了一个循环。 –

+1

它看起来效率低下,应该存在一个不那么天真的解决方案 – AdamSkywalker

1

首先,间隔(a, b)其中(a > b),我们可以轻松地将其分成两个区间

(a , 23) and (0, b) 

所以,这个问题成为寻找(a , b)(a1, b1)之间的重叠与a <= b and a1 <= b1

所以,有四个案例:

  • b < a1b1 < a,这意味着不存在重叠,则返回0
  • a <= a1 && b1 <= b,这意味着(a, b)包含(a1, b1),返回b1 - a1 + 1
  • a1 <= a && b <= b1,这意味着(a1, b1)包含(a, b),返回b - a + 1
  • 最后一种情况下是(a, b)并且每个(a1, b1)重叠部分间隔,重叠间隔是(max(a1, a), min(b, b1))
2

你可以做到这一点,而无需创建一个数组,只需calculat间隔之间的交叉点。有三种情况:

  1. 没有拆分间隔。
  2. 一个拆分间隔。
  3. 两个间隔都被分割。

您可以将分裂间隔问题分解为两个单独的间隔。使用递归,你可以很容易地做到这一点:

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); 
     } 
    } 
} 
+0

我认为这两个时间间隔都被分开的情况并不需要明确地加以说明:当第一种情况用递归调用进行处理时,它永远不会(必须)到达最终的'else'情况。尽管如此,+1的明确描述和(工作和有效的)解决方案。 – Marco13

0

检查此链接在这里:Ideone link

编辑:插入从这里的链接代码:

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+""); 
    } 
}