2016-01-19 27 views
6

Ho cercato di capire l'algoritmo per trovare il numero di ore che si sovrappongono tra due intervalli di tempo, ad esempio:Algoritmi - Trova la durata degli intervalli sovrapposti in un mondo ciclico (24 ore)

enter image description here

deve restituire 12.

E

enter image description here

Dovrebbe restituire 4.

Quindi, per favore mi aiuti a colmare le lacune nel creare la seguente funzione:

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

Grazie.

MODIFICA: Sono a conoscenza della soluzione di creare due array binari, utilizzando AND e riassumendo il risultato. Significato:

enter image description here

Ma non sarebbe aiutare i miei bisogni specifici in quanto voglio usare l'idea dell'algoritmo per una query solr, così utilizzando gli array e gli operatori binari non è un'opzione per me.

+0

Nel secondo esempio, come è l'intervallo interrotto? Come lo rappresenteresti in startTime e endTime? –

+0

@RahulJain 'startTime = 12',' endTime = 2'. è un mondo ciclico. – Daniel

+0

Ho cercato di inserire il codice per te ma StackOverflow mi avvisa che il rientro non è corretto –

risposta

3

Sorprendentemente molti ans wers in breve tempo ...

ho seguito la stessa idea che è stato già proposto in altre risposte: Quando il tempo di avvio s è inferiore al tempo di fine e, allora il risultato può essere suddiviso in due calcoli separati, per gli intervalli [s,24] e [0,e].

Questo può essere fatto "a vicenda", quindi ci sono solo 3 semplici casi da considerare, e i restanti possono essere fatti con chiamate ricorsive.

Tuttavia, ho cercato di

  • considerare il fatto che (secondo le immagini), i punti finali dovrebbero essere inclusiva (!)
  • aggiungere alcuni casi di test
  • Visualizza le configurazioni ben :-)

Questo è il risultato come 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)); 
    } 
} 

I primi due casi di test sono quelli che hanno è stata data nella domanda e stampa correttamente 12 e 4, rispettivamente. I due rimanenti sono test utilizzati in altre configurazioni di sovrapposizione:

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

Tuttavia, si noti che ulteriori configurazioni di test possono essere creati per coprire tutti i casi possibili.

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

Questo metodo dovrebbe funzionare per ciò che si desidera che faccia. Ha funzionato per me. Non sono sicuro della parte di avvolgimento.

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

Questo nuovo codice dovrebbe fare quello che vuoi. Si aggira intorno a un periodo di 24 ore.

+0

Non riesco a fare in modo che l'orario di inizio// ** sia minore delle ore di fine */'ipotesi. nel secondo esempio 'startTime' è più grande di' endTime'. – Daniel

+0

Ho aggiunto un ciclo ad esso ora. –

+1

sembra inefficiente, dovrebbe esistere una soluzione meno ingenua – AdamSkywalker

1

In primo luogo, per l'intervallo (a, b) che (a > b), possiamo facilmente spezzare in due intervalli

(a , 23) and (0, b) 

Quindi, il problema diventano trovare la sovrapposizione tra (a , b) e (a1, b1) con a <= b and a1 <= b1

Quindi, ci sono quattro casi:

  • b < a1 o b1 < a, il che significa che non v'è alcuna sovrapposizione, tornare 0
  • a <= a1 && b1 <= b, il che significa (a, b) contiene (a1, b1), tornare b1 - a1 + 1
  • a1 <= a && b <= b1, il che significa (a1, b1) contiene (a, b), tornare b - a + 1
  • ultimo caso è (a, b) e (a1, b1) parte sovrapposta di ciascun intervallo, l'intervallo di sovrapposizione è (max(a1, a), min(b, b1))
2

È possibile farlo senza creare un array, basta calcolarlo intersezioni tra intervalli. Esistono tre casi:

  1. Nessun intervallo di intervalli.
  2. Un intervallo suddiviso.
  3. Entrambi gli intervalli sono suddivisi.

È possibile risolvere il problema degli intervalli suddivisi come due intervalli separati. Utilizzando la ricorsione è possibile farlo facilmente:

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

Penso che il caso che entrambi gli intervalli siano divisi non deve essere coperto esplicitamente: quando i primi casi sono trattati con chiamate ricorsive, non arriverà mai (dover) al caso finale 'else'. Tuttavia, +1 per la descrizione chiara e la soluzione (funzionante ed efficiente). – Marco13

0

controllare questo link qui: Ideone link

EDIT: inserito il codice dal link qui:

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