Rettangolo più grande nella matrice 2d


26

Ingresso

Il tabellone: ​​un contenitore 2D (matrice, elenco di elenchi, ecc.) Di lettere come:

  ["B", "C", "C", "C", "C", "B", "B", "C", "A", "A"],
  ["B", "A", "C", "B", "B", "A", "B", "B", "A", "A"],
  ["B", "C", "B", "C", "A", "A", "A", "B", "C", "B"],
  ["B", "B", "B", "A", "C", "B", "A", "C", "B", "A"],
  ["A", "A", "A", "C", "A", "C", "C", "B", "A", "C"],
  ["A", "B", "B", "A", "A", "C", "B", "C", "C", "C"],
  ["C", "B", "A", "A", "C", "B", "B", "C", "A", "A"]

Se si sceglie un elenco di elenchi, è possibile supporre che tutti gli elenchi secondari abbiano la stessa lunghezza.

Regole

  • Per creare un rettangolo valido sono necessari tutti gli angoli del rettangolo con la stessa 'lettera'.
  • Esempio, guarda la scheda campione con X a soffietto. Puoi vedere 'X' su (1,0) anche su (4,0) anche su (1,3) e su (4,3) quindi hai la rectange [1,0,4,3] che significa da Da (1,0) a (4,3):

Scheda campione con X :

  ["B", "X", "C", "C", "X", "B", "B", "C", "A", "A"],
  ["B", "A", "C", "B", "B", "A", "B", "B", "A", "A"],
  ["B", "C", "B", "C", "A", "A", "A", "B", "C", "B"],
  ["B", "X", "B", "A", "X", "B", "A", "C", "B", "A"],
  ["A", "A", "A", "C", "A", "C", "C", "B", "A", "C"],
  ["A", "B", "B", "A", "A", "C", "B", "C", "C", "C"],
  ["C", "B", "A", "A", "C", "B", "B", "C", "A", "A"]
  • L'obiettivo è trovare il rettangolo o uno dei rettangoli con l'area più grande, calcolato da (destra-sinistra + 1) * (in basso-in alto + 1)
  • Se sono presenti più rettangoli con la stessa area massima, emettere uno qualsiasi. Opzionalmente quello con (coordinata superiore, coordinata sinistra, coordinata destra, coordinata inferiore) lessicograficamente più piccolo.
  • I rettangoli devono avere bordi paralleli al bordo della scheda.
  • Ogni lettera è un carattere ASCII stampabile dalla A alla Z (entrambi inclusi).

Produzione

L'output dovrebbe essere le posizioni verso l'alto e verso il basso verso il basso degli angoli del rettangolo dell'area più grande. Per la prima "tavola" campione il quadrato grande è quello giallo:

inserisci qui la descrizione dell'immagine

E la risposta dovrebbe essere:

[1, 1, 8, 4]

Un secondo esempio di test case

Un input di:

["C", "D", "D", "D", "A", "A"],
["B", "D", "C", "D", "A", "A"],
["B", "D", "D", "C", "A", "C"],
["B", "D", "B", "C", "A", "C"]

Dovrebbe dare uno di questi tre elenchi di coordinate che identificano un'area sei rettangoli:

[1, 0, 2, 2]
[1, 0, 3, 1]
[3, 2, 5, 3]

Questa domanda è pubblicata su Stack Overflow con il titolo: Come trovare il rettangolo più grande in un array 2D formato da quattro angoli identici? e con questa scortese soluzione JS (posso dire "scortese" perché è il mio codice;):

Ok, è il mio primo post, sii tollerante con me per favore. Cambierò tutto ciò che dici per migliorare il quiz.


7
Ciao, benvenuto in PPCG! Questa sembra essere una bella sfida, ma sembra non avere alcun criterio vincente. In genere, i post qui sono taggati [code-golf], il che significa che vince il codice più corto (in byte).
Conor O'Brien,

1
Ho pensato di farti sapere che abbiamo una sandbox che puoi utilizzare per ottenere feedback sulle domande prima che vengano pubblicate sul sito principale. Il sandbox è utile praticamente per tutti qui, ma soprattutto per i principianti, che potrebbero non conoscere tutte le regole e le aspettative che abbiamo.
Wheat Wizard

2
Alcune risposte generano le coordinate in ordine per il "primo" rettangolo (ovvero, in alto, a sinistra, in basso, a destra) anziché in (a sinistra, in alto, a destra, in basso), come mostrato nei tuoi esempi. Va bene?
nimi,

2
Formati di output meno rigorosi di solito incoraggiano più risposte, quindi anche qualcosa di simile ((left,top),(right,bottom))dovrebbe andare bene. Ho cancellato la mia risposta e rispondo di nuovo quando la domanda è completamente raffinata.
Angs

1
Certo, se stai per accettare una risposta dovrebbe essere la più breve in assoluto, è così che alla maggior parte delle persone piacciono le cose fatte sul sito. Tuttavia non vi è alcuna conseguenza per non farlo. C'è anche un'opinione crescente che accettare le risposte è dannoso per il sito. Sono di questo parere e quindi non accetto mai risposte sulle mie sfide. Quello che fai dipende da te.
Wheat Wizard

Risposte:


6

Python 2 , 148 130 byte

lambda x,e=enumerate:min(((a-c)*(d-b),b,a,d,c)for a,y in e(x)for c,k in e(x)for b,g in e(y)for d,h in e(y)if g==h==k[b]==k[d])[1:]

Provalo online!


Ciao @ovs, è per te e scomodo se cambio la regola per capire l'area in: (x2-x1 + 1) × (y2-y1 + 1) come ha suggerito Angs?
danihp,

Vorrei rilassare alcune regole per incoraggiare più risposte. Posso?
danihp,

@danihp Vai avanti. Questo non invalida la mia risposta, giusto?
Ovs,

No, la tua risposta è giusta! Bello.
danihp,

5

Retina , 163 162 byte

Lw$`(?<=(.*\n)*((.)*))(?=(.))((.)*(?<=(.*))\4)((.*\n)*((?>(?<-3>.)*)(?=\4)(?>(?<-6>.)*))\4)?
$.7,$#1,$.2,-$.($5$#9*$5),$.2,$#1,$.7,$.($#1*_$#9*
4{N`
)m`^.*?,

0G`

Provalo online! Modifica: salvato 1 byte perché il trailing )corrispondente a $.(è implicito. Spiegazione:

Lw$`(?<=(.*\n)*((.)*))(?=(.))((.)*(?<=(.*))\4)((.*\n)*((?>(?<-3>.)*)(?=\4)(?>(?<-6>.)*))\4)?

Questa espressione regolare corrisponde ai rettangoli. I gruppi sono i seguenti: 1) Riga superiore (come conteggio delle acquisizioni) 2) Colonna sinistra (come lunghezza) 3) Bilanciamento per garantire l'allineamento degli angoli sinistro 4) Lettera per gli angoli 5) Larghezza + 1 (come lunghezza) 6) Bilanciamento per garantire l'allineamento degli angoli di destra 7) Colonna di destra (come lunghezza) 8) inutilizzata 9) Altezza (come conteggio delle acquisizioni). L' wopzione assicura che tutte le possibili larghezze di rettangoli siano abbinate per ogni dato angolo in alto a sinistra. Le $opzioni elencano i risultati usando il seguente modello di sostituzione.

$.7,$#1,$.2,-$.($5$#9*$5),$.2,$#1,$.7,$.($#1*_$#9*

Le sostituzioni sono le seguenti: la colonna di destra, la riga superiore, la colonna di sinistra, la negazione dell'area del rettangolo (letteralmente calcolata come la lunghezza della ripetizione della stringa di larghezza di un numero di volte superiore all'altezza), la colonna di sinistra , la riga superiore, la colonna di destra, seguita da un'espressione che restituisce la riga inferiore (un'acquisizione sarebbe costata 12 byte più ho esaurito le variabili a cifra singola). Le prime quattro acquisizioni rappresentano l'ordinamento in ordine di priorità. Poiché Retina ordina stabilmente, è possibile stabilire un ordinamento a più colonne ordinando per ciascuna colonna di ordinamento a turno dalla priorità meno alla massima. (L'area deve essere ordinata in ordine decrescente, quindi non è possibile utilizzare un singolo ordinamento di stringhe.)

4{N`

Vengono quindi eseguiti quattro ordinamenti numerici.

)m`^.*?,

La colonna di ordinamento viene quindi eliminata dopo ogni ordinamento.

0G`

La prima voce è quindi ora il risultato desiderato.

Nota: la restrizione sulla scelta del rettangolo di una data area è stata da allora allentata e la seguente versione di 144 byte a 144 preferisce un rettangolo più largo piuttosto che più alto:

Lw$`(?<=(.*\n)*((.)*))(?=(.))((.)*(?<=(.*))\4)((.*\n)*((?>(?<-3>.)*)(?=\4)(?>(?<-6>.)*))\4)?
-$.($5$#9*$5);$.2,$#1,$.7,$.($#1*_$#9*
N`
0G`
.*;

Provalo online!


Non soddisfa il requisito lessicografico (ad esempio, provare il caso di test che ho aggiunto all'OP) (forse anche l'output può essere nell'ordine sbagliato ??) TIO
Jonathan Allan,

(... sì, i primi due valori in uscita sono nel modo sbagliato, credo)
Jonathan Allan,

Ho semplicemente allentato alcune restrizioni (requisito lessicografico-min). Spero di non essere un problema per te.
danihp,

... questo ora dovrà abbinare linee e punti.
Jonathan Allan,

Riparare l'ordine lessicografico costa 20 byte :-( e ho notato che il calcolo dell'area è cambiato, che costa altri 2 byte, ma non so cosa significhi @JonathanAllan sui punti.
Neil

4

Jelly , (27?)  29  28 byte

27 se è consentita l'indicizzazione basata su 1: rimuovere il trailing

Fṙ1s2;Uœị³EaZI‘P
ZLpLŒċÇÞṪF’

Un programma completo.

Provalo online! (o vedi l'altro caso di test )

Come?

Fṙ1s2;Uœị³EaZI‘P - Link 1, areaOrZero: list of pairs [[b,l],[t,r]]
F                - flatten the input                 [b,l,t,r]
 ṙ1              - rotate left one                   [l,t,r,b]
   s2            - split into twos                   [[l,t],[r,b]]
      U          - upend the input                   [[l,b],[r,t]]
     ;           - concatenate                       [[l,t],[r,b],[l,b],[r,t]]
         ³       - program's input
       œị        - multidimensional index into
          E      - all equal?                       X
            Z    - transpose the input              [[b,t],[l,r]]
           a     - logical AND (vectorises)         (if not X we now have [[0,0],[0,0]]
             I   - incremental differences          [t-b,r-l] (or [0,0] if not X)
              ‘  - increment (vectorises)           [t-b+1,r-l+1] (or [1,1] if not X)
               P - product                          area (or 1 if not X)

ZLpLŒċÇÞṪF’ - Main link: list of lists
Z           - transpose the input
 L          - length
   L        - length of the input
  p         - Cartesian product
    Œċ      - pairs with replacement
       Þ    - (stable) sort by:
      Ç     -   last link (1) as a monad
        Ṫ   - tail (note that the rightmost pre-sort represents the bottom-right 1x1
            -       so cannot be superseded by a non-matching rectangle)
         F  - flatten
          ’ - decrement (vectorises) (to get to 0-based indexing)

4

Perl 6 , 83 73 byte

{([X] (^$^a[0]X ^$a)xx 2).max:{[eq] $a[.[*;1];.[*;0]]and[*] 1 X-[Z-] $_}}

Provalo online!

Restituisce un elenco di elenchi ((x0 y0) (x1 y1)).

Spiegazione

{
  ([X]                   # Cross product of corner pairs.
    (^$^a[0]             # Range of x coords.
     X                   # Cross product of coords.
     ^$a                 # Range of y coords.
    )xx 2                # Duplicate list.
  ).max:                 # Find maximum of all ((x0 y0) (x1 y1)) lists
  {                      # using the following filter.
    [eq]                 # All letters equal?
      $a[.[*;1];.[*;0]]  # Multidimensional subscript with y and x coord pairs.
    and                  # Stop if false.
    [*]                  # Multiply
      1 X-[Z-] $_        # for each axis 1 - (c0 - c1) == c1 - c0 + 1.
  }
}

3

Haskell , 144 byte

import Data.Array
o=assocs
f r=snd$maximum[((c-a+1)*(d-b+1),[a,b,c,d])|((a,b),x)<-o r,((c,d),y)<-o r,x==y,r!(a,d)==r!(c,b),x==r!(a,d),a<=c,b<=d]

Provalo online!


Puoi rimuoverlo b<=d, finché tieni a<=c.
Wheat Wizard

@ovs in realtà non funzionerà neanche (vedi l'esempio che ho aggiunto TIO )
Jonathan Allan

@nimi: potrei sostenere che si tratta solo di trasporre l'input.
Angs

Va bene per me. È possibile trasporre l'ingresso.
danihp,

3

Gelatina , 24 byte

XLṭLp`€p/⁺œị€EɗÐfI‘PɗÞ0Ṫ

Provalo online!

si rivela utile.

Formato di output: [in alto, in basso], [a sinistra, a destra] . 1-indicizzazione.


3

JavaScript (ES6), 121 byte

-1 byte grazie a @ l4m2
-1 byte grazie a @tsh
+2 byte per rispettare la nuova regola di punteggio del rettangolo

Accetta input come una matrice di stringhe. Restituisce le coordinate indicizzate 0: [x0, y0, x1, y1] .

a=>a.map(b=(r,y)=>r.map((v,x)=>a.map((R,Y)=>R.map((V,X)=>V+R[x]+r[X]!=v+v+v|(A=(x+~X)*(y+~Y))<b||(o=[x,y,X,Y],b=A)))))&&o

Provalo online!


a=>a.map(b=(r,y)=>r.map((v,x)=>a.map((R,Y)=>R.map((V,X)=>V+R[x]+r[X]!=v+v+v|(A=(X-x)*(Y-y))<=b||(o=[x,y,X,Y],b=A)))))&&o
l4m2

Se sono presenti più rettangoli con la stessa area massima, emettere uno qualsiasi ; forse (A=...)<=b-> (A=...)<b?
TSH

@tsh Ora è davvero sicuro. Grazie!
Arnauld


1

Java 8, 208 205 byte

m->{int r=0,R[]={},i=m.length,j,y,z,u,t,T;for(;i-->0;)for(j=m[i].length;j-->0;)for(y=i*j;y-->0;)if((T=m[i][j])==m[u=y/j][z=y%j]&T==m[i][z]&T==m[u][j]&r<(t=(i-u)*(j-z))){r=t;R=new int[]{z,u,j,i};}return R;}

Si può sicuramente giocare a golf .. Ora uso l'approccio più ovvio di usare quattro tre cicli for nidificati.

-3 byte grazie a @ceilingcat che combina i loop interni di righe e colonne in un singolo loop.

Spiegazione:

Provalo online.

m->{                         // Method with char-matrix parameter and int-array return-type
  int r=0,                   //  Largest area found, starting at 0
      R[]={},                //  Result coordinates, starting empty
      i=m.length,j,          //  x,y indices of the first corner
      y,z,                   //  x,y indices of the second corner
      u,t,T;                 //  Temp integers to reduce bytes
  for(;i-->0;)               //  Loop `i` over the rows
    for(j=m[i].length;j-->0;)//   Inner loop `j` over the columns
      for(y=i*j;y-->0;)      //    Inner loop over the rows and columns
        if((T=m[i][j])==m[u=y/j][z=y%j]
                             //      If the values at coordinates [i,j] and [y,z] are equal
           &T==m[i][z]       //      as well as the values at [i,j] and [i,z]
           &T==m[u][j]       //      as well as the values at [i,j] and [y,j]
           &r<(t=(i-u)*(j-z))){
                             //      And the current area is larger than the largest
          r=t;               //       Set `r` to this new largest area
          R=new int[]{z,u,j,i};}
                             //       And save the coordinates in `R`
  return R;}                 //  Return the largest rectangle coordinates `R`
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.