2016-01-19 2 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? 
} 

Спасибо.

EDIT: Я знаю о решении создания двух двоичных массивов, используя 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)); 
    } 
} 

Первые два случая испытаний те, которые имеют были заданы в вопросе, и они правильно печатают 12 и 4, соответственно. Оставшиеся два предназначены для тестирования других конфигураций перекрытия:

......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; 
} 

Этот метод должен работать так, как вы хотите. Это сработало для меня. Хотя я не уверен в части упаковки.

EDIT

/** 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 < a1 или b1 < 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

Вы можете сделать это, не создавая массив, просто вычислите пересечения интервалов. Существует три случая:

  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

EDIT: Поставлен код по ссылке здесь:

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