Scegli il bastone più lungo


13

Sei un giovane fanatico della programmazione che vive con i tuoi altri 2 migliori amici. Ogni settimana, uno di voi deve fare tutte le faccende di casa e decidere chi è il turno selezionando un bastone. Chi sceglie il bastone più corto perde e fa tutte le faccende.

Dato che tutti voi siete programmatori e amate creare enigmi, avete modificato il "Scegli lo stick più corto" in un puzzle per computer.

Ecco le regole del puzzle.

  1. Ti verrà data una matrice 2D, in cui ogni colonna rappresenta un bastone.
  2. In ogni colonna, 1 rappresenta una porzione dello stick e 0 è uno spazio vuoto
  3. Quando si va dall'alto verso il basso in ogni colonna, inizialmente ce ne sono 0e non appena si preme a 1, il bastone si è avviato e il resto della colonna sarà riempito 1solo con
  4. Puoi scrivere il tuo programma per scegliere una colonna. La dimensione del bastone in quella colonna determina il vincitore / perdente. Dimensione dello stick == numero di 1 in quella colonna.
  5. Tuttavia, quel programma può avere solo una complessità temporale peggiore lineare.

Dato che tutti voi siete programmatori, saprete se il programma di qualcun altro sta rispettando il limite di complessità temporale.

Il tuo compito è:

  • Scrivi un programma o una funzione che accetta input in formato 2D o array di stringhe.
  • L'input può essere preso da STDIN / prompt / console o da un argomento di funzione.
  • Se stai leggendo l'input da STDIN / prompt, puoi presumere che la lettura dell'input e la sua conversione in un array richiedano 0 tempo (anche se il codice per farlo deve essere presente nella tua risposta)
  • Determina la colonna con il bastone più lungo al suo interno.
  • L'output può essere il valore di ritorno della funzione o su STDOUT / console / avviso.
  • Il programma / funzione deve avere una complessità temporale nel caso peggiore, O(m+n)dove si mtrova il numero di righe e nil numero di colonne.

L'input può essere uno dei seguenti formati:

Matrice 2D:

[ [0, 0, 0, 0],
  [1, 0, 0, 0],
  [1, 1, 0, 1],
  [1, 1, 1, 1] ]

Matrice di stringhe:

[ "0000", "1000", "1101", "1111" ]

L'input avrà le seguenti proprietà:

  • Le dimensioni dell'array sono sconosciute, si assume un rettangolo di qualsiasi dimensione
  • In qualsiasi colonna, scendendo dall'alto in basso, se vedi un 1, allora tutto sotto sarà uno
  • Sono consentite le colonne vuote (ovvero lunghezze 0) .

Questo è un codice-golf, quindi vince il codice più corto ! *

Spiega il tuo codice o fornisci la versione non controllata (per verificare la complessità temporale) insieme a quale dei due formati di input ti aspetti.

AGGIORNAMENTO Qui la complessità del tempo lineare significa O (n + m) dove n è la dimensione della colonna e m la dimensione della riga. (Per coloro che non erano chiari)

AGGIORNAMENTO 2 Questo sicuramente può essere fatto in tempo lineare. E se stai postando una risposta, non esitare a posticipare la logica / l'algoritmo di un paio di giorni per una lotta leale :)

AGGIORNAMENTO 3 Esaminerò tutte le risposte tra un paio d'ore per convalidare la complessità temporale e il programma :)


2
Direi che questo non può essere fatto in O (n + m), poiché ogni cella potrebbe contenere il valore cruciale (cioè il primo "1" del bastone / colonna più lungo). Quindi devi guardare ogni cella, che richiede O (n * m).
Falko,

Potrebbero esserci colonne vuote?
Martin Ender,

@Optimizer: Oh, capisco. Hai ragione. :)
Falko,

11
Non può essere fatto in O (n + m). Una volta che l'input è stato convertito in un formato che consente l'accesso casuale, l' elaborazione rimanente può essere O (n + m), ma è necessario scrivere un programma e, nel peggiore dei casi, l'unico 1nell'input è l'ultima cella quindi è necessario leggere l'intero input. Anche se la libreria standard di una lingua falsa l'accesso casuale allo stdin, sotto le scene lo sta tamponando e quindi il tempo impiegato è Omega (n * m).
Peter Taylor,

2
Se si desidera consentire alle persone di " semplicemente creare una funzione che accetta un array ", la domanda non dovrebbe affermare che devono scrivere un programma. E se hai bisogno di soluzioni che sono in O (N ^ 0,5) dove N è la dimensione dell'input, non dovresti chiedere soluzioni temporali lineari. Una soluzione di tempo lineare può leggere l'intero input.
Peter Taylor,

Risposte:


4

GolfScript, 45 caratteri

:^,:y;0:x{^y(=x=2%y*{y(:y;x\}{x):x}if^0=,<}do

Prende l'input come una matrice di stringhe, restituisce l'indice (basato su 0) della colonna più alta. Viene eseguito in iterazioni O ( righe + colonne ) e ogni iterazione dovrebbe richiedere essenzialmente un tempo costante (almeno ipotizzando un calcolo a tempo costante). Le uniche operazioni di matrice / stringa eseguite all'interno del ciclo sono le ricerche di elementi ( =) e la lunghezza di una stringa ( ,), che richiedono entrambe un tempo costante in GolfScript.

Provalo online.

Spiegazione:

Come la maggior parte delle soluzioni qui, questo codice funziona iniziando nell'angolo in basso a sinistra della matrice, camminando verso l'alto o verso destra a seconda che l'elemento corrente della matrice sia 1 o 0 e tenendo traccia della colonna in cui è stata spostata l'ultima volta .

All'inizio del programma, assegno l'array di input alla variabile ^, la sua lunghezza (ovvero il numero di righe) ae y0 a x. Anche il valore 0 viene lasciato nello stack; durante il ciclo seguente, verrà sostituito dall'indice della colonna più alta.

All'interno del ciclo principale, ^y(=x=estrae il xcarattere y-1-th della riga -th in ^. Questo in realtà restituisce il codice ASCII del carattere, quindi 2%è necessario eliminare tutto tranne l'ultimo bit. In un caso speciale, se è yuguale a 0 (che può accadere se la colonna più alta trovata finora arriva fino alla riga superiore), il bit cercato verrà effettivamente dall'ultima riga della matrice (indice -1), ma quanto segue lo y*costringe a zero, creando in tal modo una riga virtuale di zeri nella parte superiore della matrice.

Di seguito ifeseguirà uno dei due blocchi di codice che lo precedono, a seconda che il bit cercato sia diverso da zero (vero) o zero (falso). Se diverso da zero, yviene decrementato di uno e il valore corrente xsostituisce l'indice di colonna più alto nello stack (con il valore precedente lasciato temporaneamente sopra di esso). Se zero, xviene semplicemente incrementato di uno (e temporaneamente lasciato in pila, in cima all'indice di colonna più alto).

Infine, ^0=estrae la prima riga della matrice, ,restituisce la sua lunghezza e la <confronta con l'indice di colonna temporaneamente lasciato sulla pila (che sarà uguale xse fosse appena incrementato) Se l'indice è inferiore alla lunghezza della riga, il ciclo ripete.

Ps. Sulla base del mio test, dovrebbe essere possibile abbreviare questo programma di un carattere sostituendo il test di lunghezza della stringa ,<alla fine del ciclo con >, che taglia la stringa in corrispondenza dell'indice dato e restituisce la parte finale (che sarà vuota, e quindi falso, alla fine del ciclo). Tuttavia, mentre il taglio di una stringa del genere sembra essere implementato come un'operazione a tempo costante in GolfScript (o, piuttosto, in Ruby, su cui GolfScript viene eseguito), non ho trovato alcuna documentazione ufficiale che lo dica. Per sicurezza, ho scelto di presentare la versione leggermente più lunga, ma sicuramente O (1) sopra.


6

Rubino, 83 75 68 66 63 byte

f=->m{m[b=c=i=0].map{(c=i;b-=1)while(r=m[b-2])&&r[i]>0;i+=1};c}

Definisce una funzione fche assume la forma di matrice 2D come input.

Sto iniziando in basso a sinistra, tenendo traccia della lunghezza massima dello stick (in realtà, meno quella) e della colonna corrispondente. In ogni colonna, se ci sono ancora 1s sopra la lunghezza massima precedente dello stick, cammino verso l'alto fino alla fine e ricordo la nuova lunghezza massima e colonna. Ciò significa che sto ripetendo una volta lungo le colonne e al massimo una volta lungo le righe (in particolare sto ripetendo fino alla lunghezza massima dello stick), che è precisamente O(m+n).


@Optimizer Non ho visto la tua seconda modifica fino a quando non l'ho pubblicata, quindi era comunque nella cronologia delle modifiche. Ecco perché l'ho appena messo in uno spoiler per le persone che vogliono capirlo da soli.
Martin Ender,

4

Python 2 - 71, 69, 73, 75 81

j=i=-1
M=input()
for m in M[0]:
 j+=1
 while-i<len(M)and M[i][j]:i-=1;J=j
print J

È previsto che venga eseguito in Python 2 o 3? Come dovrebbe apparire l'input?
feersum

1
@feersum Python 2, l'array di array.
Justin,

@feersum: Quincunx ha ragione. L'input è un array 2D di ints, come hai suggerito.
Falko,

Non iandrà oltre i limiti se un bastone occupa un'intera colonna?
xnor

1
Siamo spiacenti, ma sembra che il jconteggio delle modifiche 0interrompa la condizione del ciclo i*j.
xnor

2

C, 64 byte

Modifica: ho imparato che la domanda richiede la posizione della colonna più lunga e non la sua lunghezza.

La prima riga è il codice golf e il resto è l'invocazione di esempio.

g(int m,int n,int**a,int*r){for(*r=n;n*m;a[m][n]?m--,*r=n:--n);}

/* usage:
    m = number of rows
    n = number of columns
    a = 1-based 2D array such that a[i][j] gives the value at the ith row and jth column
    r = address of return value 
    Returns (to r) the 1-indexed location of a column with the longest length, or 0 if n=0
    */

int main()
{
    int flat[4*4] = {1, 0, 0, 0,
                     1, 0, 0, 1,
                     1, 1, 0, 1,
                     1, 1, 1, 1};
    int*twoD[4] = {flat-1,flat+3,flat+7,flat+11};
    int ret;
    g(4,4,twoD-1,&ret);
    printf("%d", ret);
    return 0;
}

// old function which determines longest length (65 bytes)
f(int m,int n,int**a,int*r){for(*r=m;n*m;a[m][n]?m--:--n);*r-=m;}

Degno di nota! Riesci ad abbandonare la ints nella firma della funzione per caso o non funziona a causa dei puntatori presenti?
Martin Ender,

1
L'input deve contenere solo l'array. Non è possibile indicare al programma le dimensioni dell'array.
Ottimizzatore

Aspetta, funziona davvero? Questo sembra restituire la lunghezza del bastone più lungo e non la sua posizione: ideone.com/YEzqzl
Martin Ender

2
@Ottimizer che è praticamente impossibile in C.
Martin Ender,

Potrebbe essere, ma questa è la domanda :)
Ottimizzatore,

2

C #: 236 caratteri

int p(int[,] a){int y=0,s=0,i=0,x;for(;++y<=a.GetUpperBound(0);)for(x=i;x<=a.GetUpperBound(1);){if(a[y,x++]==0)break;s=y;i++;}return s;}

ungolfed:

int p(int[,] a)
{
    int selectedRow=0;
    int maxLength=0;
    for(var y = 0; y<=a.GetUpperBound(0); y++)
        for(var x=maxLength; x<=a.GetUpperBound(1); x++)
        {
            if(a[y,x++]==0)
                break;
            selectedRow=y;
            maxLength++;
        }
    return selectedRow;
}

2

PHP 5.4 - 108 byte

(113 se includi il <?php)

Formato di input: l'array verrà letto come una stringa JSON.

php longest_stick.php "[[0, 0, 0, 0],[1, 0, 0, 0],[1, 1, 0, 1],[1, 1, 1, 1]]"

Spazio bianco aggiunto per la leggibilità: tutte le nuove righe e gli spazi iniziali possono essere rimossi.

<?php
$t=count($s=json_decode($argv[1]))-1;
foreach($s[0] as $k=>$_)
    while($s[$t][$k]) {
        $t--;
        $l = $k;
    }
echo $l?:0;

Versione minimizzata:

<?php $t=count($s=json_decode($argv[1]))-1;foreach($s[0] as $k=>$_)while($s[$t][$k]){$t--;$l=$k;}echo $l?:0;

È un po 'come rubare l'algoritmo da Martin qui, ma è bello giocare con linguaggi che non sono visti così spesso qui XD


@ MartinBüttner Ho "rubato" il tuo algoritmo, quindi dovrebbe essere O (n + m) ora. Penso che sia giusto XD
Niet the Dark Absol,

È possibile sostituire $s=json_decode($argv[1]);$t=count($s)-1;con $t=count($s=json_decode($argv[1]))-1;(-3 byte).
Blackhole,

@Blackhole In effetti puoi. Grazie!
Niet the Dark Absol,

@Blackhole Penso che ciò spezzerebbe la funzionalità. Eseguirà i compiti anche se la condizione non è soddisfatta.
Niet the Dark Absol,

@Blackhole Lo rompe ancora, temo che XD possa $t--accadere solo se la condizione è soddisfatta.
Niet the Dark Absol,

2

Cobra - 98

def f(a)
    s,x,y=0,0,a.count-1
    while y+1and x<a[0].count
        while a[y][x],y,s=y-1,x
        x+=1
    print s

2

C ++ :: 78

A differenza dell'altra soluzione C, questo è l'intero programma. (non è necessaria alcuna chiamata, non è necessario indicare alla funzione la dimensione dell'array). Sfortunatamente questo significa che è più lungo come maindeve essere usato invece di un nome di funzione a carattere singolo, devo interpretare l'input e quindi emettere la risposta, dove l'altra soluzione gestisce questo "altrove". Anche il mio primo codice golf.
compilato con g++ file.cpp -include iostream, eseguito con ./a 000 010 110 111(ad esempio) == array di stringhe (credo che ciò sia consentito nelle specifiche della domanda)

int c;main(int r,char**v){for(r--;r*v[r][c];v[r][c]-48?std::cout<<c,r--:++c);}

La versione precedente mostra l'attuale migliore trovato finora su ogni iterazione. La cifra finale in uscita è la risposta. Il passaggio dall'elaborazione in basso a sinistra anziché in basso a destra e l' 0indicizzazione ha ridotto questa soluzione di 10 (!) Caratteri.
il passaggio a c ++ elimina l'invio di un carattere in più poiché std::cout<<è più breve di putchar(-48)e dovrebbe anche supportare esplicitamente più di 9 stick con output corretto (anche se può essere più difficile differenziare ogni output)
Rimuovere il campo di risposta e produrlo direttamente tagliare altri 6 caratteri. Ora emette il meglio della corrente solo quando sale, il che interrompe almeno un po 'di output.
L'intero file ora ha una dimensione di soli 78 byte e si avvicina alla sola soluzione che l'altroCusi di presentazione. (con un sacco di codice extra per supportare detta funzione).

Come sotto la descrizione non è aggiornata:

cè globale quindi viene inizializzato con 0
rè il numero di input (righe) +1 (nome del programma)
vè l'array di stringhe con v[0]non valido (nome del programma)
Dato che è 0 indicizzato, rè fuori dai limiti, quindi decrementa.
Mentre r!=0(puntando a una stringa valida) e il carattere cnella stringa non è il terminatore null '\0'
se il carattere non è '0'
vai su una riga ( r) e visualizza la colonna ( c)
altrimenti vai alla colonna successiva ( c)

fatto

Posso giocare ancora a golf?

Codice non golfato (con output aggiuntivo):

#include <stdio.h>
#include <string.h>

int main(int argc, char* argv[])
{
  int rows = argc-1;
  int cols = strlen(argv[1]);
  int ans;

  printf("rows: %d, cols: %d\n",rows, cols);

  while((rows)&&cols)
  {
    if (argv[rows][cols-1]-'0')
    {
      printf("stick @%d,%d\n",cols,rows);
      ans = cols;
      rows--;
    }
    else
    {
      printf("no stick @%d,%d\n",cols,rows);
      cols--;
    }
  }
  printf("%d",ans);
}
Usa la lunghezza delle stringhe per scoprire il numero di colonne e argc per trovare il numero di righe. A partire dall'angolo in basso a destra, segue queste semplici regole: se la cella è un bastone, quindi spostati verso l'alto, imposta la risposta alla colonna corrente. Se la cella non è un bastoncino, spostati a sinistra. O (n + m): poiché si sposta solo verso l'alto e verso sinistra, può avere solo letture max n + m. Esce presto se cade dalla parte superiore o sinistra dell'array.


1

OCaml - 144 caratteri

let s a=Array.(let rec f i j m=if i=0then m else if a.(i).(j)=0then if j=length a.(i)-1then m else f i(j+1)m else f(i-1)j j in f(length a-1)0 0)

Prende un int array arrayinput e inizia da in basso a sinistra, spostandosi verso l'alto o verso destra se vede a 1o a 0. Il conteggio delle colonne inizia alle 0.

uso

 s [| [| 0; 0; 0; 0 |]; [| 0; 0; 1; 0|]; [| 1; 0; 1; 0 |]; [| 1; 1; 1; 0 |]; [| 1; 1; 1; 1 |] |];;
 - : int = 2

Ungolfed

let s a = Array.(
  let rec f i j m = (* m is the longest stick seen so far *)
    if i=0 then m (* A column is full: this is the longest possible stick and j=m anyway *)
    else if a.(i).(j)=0 then (* current column is shorter than a previously seen stick *)
      if j=length a.(i)-1 then m (* we have examined all columns, just return m *)
      else f i(j+1) m (* start examining next column *)
    else f (i-1) j j (* current column is longer than all the ones previously seen. Check how long the stick is *)
  in
  f (length a-1) 0 0)

0

T-SQL - 71 64

Utilizza la tabella A come input

SELECT IDENTITY(INT, 1, 1) R, A INTO A
FROM (VALUES
 ('0000')
,('1000')
,('1101')
,('1111')
) AS A(A)

E la domanda è

SELECT TOP(1)CHARINDEX('1',A)FROM A WHERE A LIKE'%1%' ORDER BY R

SQLFiddle

Ciò restituisce la prima riga dalla tabella a ordinata per r dove è presente un 1 nella stringa a.

TOP(1) limita il risultato alla prima riga restituita.

CHARINDEX('1',A) restituisce la posizione del primo 1 nella stringa o zero se non viene trovato.

WHERE A LIKE'%1%' filtra le righe in cui A contiene un 1

ORDER BY R assicura che la tabella venga letta dall'alto verso il basso


Puoi spiegare cosa sta succedendo in quel codice? : D Nessuna esperienza con T-SQL
Optimizer

Vedo, quindi il filtro su ogni riga non è un'operazione O (n * m)? cioè non complessità temporale lineare.
Ottimizzatore

Difficile da dire Il motore SQL controllerà tutte le righe per un 1 nella colonna. Restituirà solo la prima riga dall'alto verso il basso che si qualifica. Quindi, in questa situazione, analizza l'intero tavolo. Filtra le righe con la colonna contenente 1. Ordina i risultati sulla colonna identità e restituisce il primo risultato.
MickyT,

Guardalo in questo modo: cosa succede se le tue righe sono come "0000", "0000", "0000", "0001". In questo caso, dovrà andare fino all'ultima riga e fino all'ultimo carattere della riga per capire la presenza di 1
Optimizer,

1
Quindi sì, è O (m * n) quindi :)
Ottimizzatore,

0

Delphi 122 caratteri

Sigh ... è un linguaggio così voluminoso.

Aggiornamento: ho dovuto aggiungere 6 caratteri cambiando funzione il tipo restituito da I a intero. La funzione era ancora compilata poiché il programma di test aveva un "tipo I = intero;" istruzione rimasta da una versione precedente del programma.

function S(A:array of string):integer;var n,c:integer;begin n:=0; repeat c:=Pos('1',A[n]);inc(n) until c>0; result:=c;end;

Stai eseguendo la chiamata Pos () su ogni riga (nel tuo caso, stringa) dell'array?
Ottimizzatore

@Optimiser Sì, il programma cerca ogni stringa nell'array (usando 'inc (n)') fino a trovare un '1'. Il primo '1' trovato sarà il più alto (o uguale al più alto) '1', quindi la sua posizione nella stringa (le stringhe sono 1-ndex in delphi) sarà la posizione della colonna più lunga. La routine fallisce se non ci sono '1 nell'array, ma credo che questo sarebbe un input rotto in quanto non ci sarebbe quindi uno "stick più lungo" da trovare.
Penguino,

1
Quindi, prima di tutto, questo è un input valido:, in "0000", "0010", "1111"secondo luogo, la tua risposta non soddisfa il requisito di complessità temporale lineare
Optimizer

@Optimizer Sì, sarebbe un input valido e identifica correttamente il 3 ° stick. Ma mi sono reso conto dopo aver pubblicato il post che avevo convertito il mio programma N ordine valido che utilizzava array, in un programma N ^ 2 ordine non valido che utilizzava stringhe (inseguendo una riduzione da ~ 160 caratteri).
Penguino,

0

schema - 236 caratteri

Anche più a lungo della versione di Delphi ... c'è probabilmente un modo per farlo in modo molto più efficiente con lo schema. E ancora peggio: ho appena notato che è ordine m * n.

(define (s l) (cond ((eq? (cdr l) '()) (car l)) (else (map + (car l) (s (cdr l)))))) (define (u l) (define (t n p q l) (cond ((eq? l '()) p) ((< n (car l)) (t (car l) q (+ 1 q) (cdr l))) (else (t n p (+ 1 q) (cdr l))))) (t 0 0 1 (s l)))

l è un elenco del modulo '((0 0 0 0) (1 0 0 0) (1 1 0 1) (1 1 1 1)). Penso che sia una rappresentazione equa di un input di array 2D per lo schema.

(sl) somma gli ennesimi elementi di ciascuna delle sotto-liste di una lista di liste di nuimbers, quindi (s '((0 0 0 0) (1 0 0 0) (1 1 0 1) (1 1 1 1))) ritornerebbe (3 2 1 2).

(ul) restituisce l '"indice" della voce più grande di un elenco di numeri (utilizzando la funzione helper t), quindi (u' (3 2 1 2)) restituirà 1 (come l'elemento più grande "3 nell'elenco" (3 2 1 2) è in posizione 1).


Sommare tutte le liste secondarie è un'operazione O (m * n).
Martin Ender,

0

Racchetta 70

golfed:

(define(h m)(for/last([r m]#:final(memv 1 r))(length(takef r even?))))

Presuppone che l'input sia un array bidimensionale, che in Racket sarebbe un elenco di elenchi:

(define m 
  '((0 0 0 0)
    (1 0 0 0)
    (1 1 0 1)
    (1 1 1 1)))

Ungolfed:

(define (h m)
  ;; step through rows, stopping at the first that contains a 1
  (for/last ([r m] #:final (memv 1 r)) 
    (length (takef r even?)))) ; pop off the leading zeroes to get the column index

Restituisce l'indice di colonna con lo stick più lungo.


Quindi in pratica stai attraversando ogni colonna e contando il numero di 1"s"?
Ottimizzatore

Vedo il tuo punto. Algoritmo aggiornato.
Matthew Butterick,

Ciò ha ancora una complessità nel caso peggiore di O (m * n) (nel caso in cui non ci sia 1nella matrice, o solo nella riga inferiore).
Martin Ender,

0

JavaScript, ES6, 76 caratteri

W=a=>(j=>{for(k=i=a.length-1;~i&~j;)a[i][j]?(k=j,i--):j--})(a[0].length-1)|k

Accetta array di input di array.


0

JavaScript ES6, 65 byte

Accetta entrambi i formati di input

f=(a,t)=>a.reduceRight((p,c)=>t+1?t:(x=c.indexOf(1,p))+1?x:t=p,0)

Ha spiegato:

Iterati dal basso verso l'alto. Utilizza String.prototype.indexOf()o Array.prototype.indexOf()dipende dall'input su ciascun valore. Trova il primo indice di ogni riga con un 1 dall'offset precedente, se non ne trova nessuno imposta la tvariabile sull'ultimo offset e non esegue più indexOfchiamate.


indexOffunziona in uno dei due O(log n)o O(n), quindi l'algoritmo generale non sarà mai presenteO(m + n)
Optimizer

@Optimizer Sì, ho capito che era la sua O (m * n) che non stava pensando direttamente.
George Reith,

@Optimizer aggiornato per essereO(m+n)
George Reith
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.