Impostare ogni cella nella matrice su 0 se quella riga o colonna contiene uno 0


152

Data una matrice NxN con 0 e 1 secondo. Imposta ogni riga che contiene a 0su tutti 0i se imposta ogni colonna che contiene a 0su tutti i 0secondi.

Per esempio

1 0 1 1 0
0 1 1 1 0
1 1 1 1 1
1 0 1 1 1
1 1 1 1 1

risultati in

0 0 0 0 0
0 0 0 0 0
0 0 1 1 0
0 0 0 0 0
0 0 1 1 0

Un tecnico Microsoft mi ha detto che esiste una soluzione che non richiede memoria aggiuntiva, solo due variabili booleane e un passaggio, quindi sto cercando quella risposta.

A proposito, immagina che sia una matrice di bit, quindi solo 1 e 0 possono essere nella matrice.


1
Eh? Che cos'è "ogni volta che incontri"? In quale ordine stai incontrando gli elementi nella matrice? E se incontri tutti i bit, non otterrai comunque tutti gli 0?
ShreevatsaR,

Bene, l'ordine in cui decidi di incontrare gli elementi è la tua decisione, il fatto è che devi solo impostare a 0 gli elementi corretti. Se si incontrano tutti i bit impostati su 0, sì, la matrice verrà comunque riempita di zeri.
jaircazarin-old-account

Quali sono "gli elementi propri"? Ti vengono date due matrici, una la matrice "sorgente" e una una matrice "bersaglio" e devi decidere in quale ordine "incontrare" gli elementi in modo da ottenere la matrice "bersaglio"?
ShreevatsaR,

1
Penso che tu abbia capito qualcosa per il pensiero "1 passaggio". Può essere fatto linearmente in 2 passaggi sebbene, senza memoria aggiuntiva, solo 2 booleani ;-) Quindi presumo fortemente che sia la soluzione che intendeva (vedi sotto)
Piotr Lesnicki,

1
Puoi per favore ricontrollare con il tuo amico se la descrizione del problema è davvero corretta? Pensavo di poterlo fare con i codici di Hamming o con i bit di parità, ma finora non ho avuto successo e il problema continua a rimanere in testa. :)
CSL

Risposte:


96

Ok, quindi sono stanco perché sono le 3 del mattino, ma ho un primo tentativo sul posto con esattamente 2 passaggi su ciascun numero nella matrice, quindi in O (NxN) ed è lineare nella dimensione della matrice.

Uso la prima colonna e la prima riga come marker per sapere dove sono le righe / i col solo 1. Quindi, ci sono 2 variabili l e c da ricordare se anche la prima riga / colonna sono tutte 1. Quindi il primo passaggio imposta i marker e reimposta il resto su 0.

Il secondo passaggio imposta 1 nei punti in cui le righe e i punti sono contrassegnati come 1 e reimposta la prima riga / i a seconda di l e c.

Dubito fortemente che possa essere fatto in 1 passaggio poiché i quadrati all'inizio dipendono dai quadrati alla fine. Forse il mio secondo passaggio può essere reso più efficiente ...

import pprint

m = [[1, 0, 1, 1, 0],
     [0, 1, 1, 1, 0],
     [1, 1, 1, 1, 1],
     [1, 0, 1, 1, 1],
     [1, 1, 1, 1, 1]]



N = len(m)

### pass 1

# 1 rst line/column
c = 1
for i in range(N):
    c &= m[i][0]

l = 1
for i in range(1,N):
    l &= m[0][i]


# other line/cols
# use line1, col1 to keep only those with 1
for i in range(1,N):
    for j in range(1,N):
        if m[i][j] == 0:
            m[0][j] = 0
            m[i][0] = 0
        else:
            m[i][j] = 0

### pass 2

# if line1 and col1 are ones: it is 1
for i in range(1,N):
    for j in range(1,N):
        if m[i][0] & m[0][j]:
            m[i][j] = 1

# 1rst row and col: reset if 0
if l == 0:
    for i in range(N):
        m [i][0] = 0

if c == 0:
    for j in range(1,N):
        m [0][j] = 0


pprint.pprint(m)

Un problema qui è se n> sizeof (c) quindi si rompe. Per espanderlo in modo che funzioni nel caso generale di n, è necessario ridimensionare dinamicamente il campo di bit, che a mio avviso violerebbe il vincolo dato dal problema.
Adam,

No, c non è un bitfield, è solo un bool. & = Non è un bit per bit (beh, lo è, ma su un valore di 1 bit), è lì perché c ti dice se la prima colonna è tutta 1 (vero) o contiene uno 0 (falso).
Steve Jessop,

2
Non riesce se la riga superiore è [0,1,1,1 ...] La mia correzione di bug è di inizializzare da l a m [0] [0] anziché 1
paperhorse,

in effetti l = 1 per i nell'intervallo (1, N): l & = m [0] [i] dovrebbe essere l = 1 per i nell'intervallo (N): l & = m [0] [i]
Kristof Neirynck

1
A proposito, credo che la condizione nel secondo passaggio dovrebbe essere qualcosa del genere: if m [i] [0] | m [0] [j]:
jaircazarin-old-account

16

Questo non può essere fatto in un passaggio poiché un singolo bit ha un effetto sui bit prima e dopo in qualsiasi ordine. IOW Qualunque sia l'ordine in cui attraversi l'array, potresti in seguito imbatterti in uno 0, il che significa che devi tornare indietro e cambiare un precedente 1 in uno 0.

Aggiornare

Le persone sembrano pensare che limitando N a un valore fisso (diciamo 8) è possibile risolvere questo passaggio. Bene questo è a) manca il punto eb) non la domanda originale. Non vorrei pubblicare una domanda sull'ordinamento e non mi aspetto una risposta che abbia iniziato "supponendo che tu voglia solo ordinare 8 cose ...".

Detto questo, è un approccio ragionevole se si sa che N è in effetti limitato a 8. La mia risposta sopra risponde alla domanda originale che non ha tale ritrattazione.


Non può essere eseguito in un passaggio senza memoria aggiuntiva. Può essere fatto in un passaggio se c'è un'altra matrice NxN in cui memorizzare i risultati. Allo stesso modo, con alcuni bit twiddles e due passaggi può essere fatto senza memoria aggiuntiva.
paxos1977,

2
Non puoi ancora farlo in un solo passaggio anche se usi una matrice temporanea, altrimenti c'è qualcosa di strano che non sto arrivando qui. È necessario un passaggio per dedurre le informazioni sulla riga / colonna e uno per impostare tutto.
Lasse V. Karlsen,

Ho risolto questo problema riconoscendo che esiste un solo valore unico diverso da zero per riga e assegnandolo semplicemente per riferimento.
Daniel Papasian,

@ceretullis, lassevk: penso ancora che non si possa fare in un solo passaggio. I passaggi su quella seconda matrice dovrebbero essere conteggiati, altrimenti potresti semplicemente copiare la matrice in un solo passaggio e lavorare con la copia come desideri. @Daniel Papasian: La tua soluzione non scala dove N> #bits in int / long / qualunque
Draemon

Draemon, la tecnica si adatta bene, è solo matematica - puoi costruire hardware che lo fa, oppure puoi usare tecniche software per manipolare numeri più grandi della tua parola. Nessuno dei due viola i vincoli del problema, IMHO
Daniel Papasian,

10

Quindi la mia idea è quella di utilizzare i valori nell'ultima riga / colonna come flag per indicare se tutti i valori nella colonna / riga corrispondente sono 1s.

Usando una scansione Zig Zag attraverso l'intera matrice TRANNE la riga / colonna finale. Ad ogni elemento, si imposta il valore nell'ultima riga / colonna come AND logico di se stesso con il valore nell'elemento corrente. In altre parole, se si preme uno 0, la riga / colonna finale verrà impostata su 0. Se si ottiene un 1, il valore nella riga / colonna finale sarà 1 solo se era già 1. In ogni caso impostare l'elemento corrente su 0.

Al termine, la riga / colonna finale dovrebbe avere 1 se la colonna / riga corrispondente è stata riempita con 1s.

Esegui una scansione lineare attraverso l'ultima riga e colonna e cerca 1 secondo. Impostare 1s negli elementi corrispondenti nel corpo della matrice in cui la riga e la colonna finali sono entrambe 1.

Codificare sarà complicato evitare errori off-by-one, ecc., Ma dovrebbe funzionare in un unico passaggio.


Molto bello ... Stavo pensando sulle stesse linee, ma mi mancava di usare l'ultima riga / colonna per memorizzare quelle informazioni, quindi ero bloccato con memoria aggiuntiva per un paio di array Nx1.
Dave Sherohman,

1
A me sembrano due passaggi: un passaggio è la scansione a zig-zag, il secondo è "Imposta 1s negli elementi corrispondenti nel corpo della matrice in cui la riga e la colonna finali sono entrambe 1".
Adam Rosenfield,

La scansione a zig-zag (che come qualcuno mi ha indicato non è strettamente necessaria) attraversa tutto MA l'ultima riga / colonna. Pertanto la scansione della colonna finale / riga non duplica gli elementi precedentemente scansionati. Da qui un passaggio. In altre parole è O (N ^ 2) per una matrice N * N.
Alastair,

6

Ho una soluzione qui, funziona in un unico passaggio e fa tutto l'elaborazione "sul posto" senza memoria aggiuntiva (salvo per far crescere lo stack).

Usa la ricorsione per ritardare la scrittura di zeri che, naturalmente, distruggerebbe la matrice per le altre righe e caratteri:

#include <iostream>

/**
* The idea with my algorithm is to delay the writing of zeros
* till all rows and cols can be processed. I do this using
* recursion:
* 1) Enter Recursive Function:
* 2) Check the row and col of this "corner" for zeros and store the results in bools
* 3) Send recursive function to the next corner
* 4) When the recursive function returns, use the data we stored in step 2
*       to zero the the row and col conditionally
*
* The corners I talk about are just how I ensure I hit all the row's a cols,
* I progress through the matrix from (0,0) to (1,1) to (2,2) and on to (n,n).
*
* For simplicities sake, I use ints instead of individual bits. But I never store
* anything but 0 or 1 so it's still fair ;)
*/

// ================================
// Using globals just to keep function
// call syntax as straight forward as possible
int n = 5;
int m[5][5] = {
                { 1, 0, 1, 1, 0 },
                { 0, 1, 1, 1, 0 },
                { 1, 1, 1, 1, 1 },
                { 1, 0, 1, 1, 1 },
                { 1, 1, 1, 1, 1 }
            };
// ================================

// Just declaring the function prototypes
void processMatrix();
void processCorner( int cornerIndex );
bool checkRow( int rowIndex );
bool checkCol( int colIndex );
void zeroRow( int rowIndex );
void zeroCol( int colIndex );
void printMatrix();

// This function primes the pump
void processMatrix() {
    processCorner( 0 );
}

// Step 1) This is the heart of my recursive algorithm
void processCorner( int cornerIndex ) {
    // Step 2) Do the logic processing here and store the results
    bool rowZero = checkRow( cornerIndex );
    bool colZero = checkCol( cornerIndex );

    // Step 3) Now progress through the matrix
    int nextCorner = cornerIndex + 1;
    if( nextCorner < n )
        processCorner( nextCorner );

    // Step 4) Finially apply the changes determined earlier
    if( colZero )
        zeroCol( cornerIndex );
    if( rowZero )
        zeroRow( cornerIndex );
}

// This function returns whether or not the row contains a zero
bool checkRow( int rowIndex ) {
    bool zero = false;
    for( int i=0; i<n && !zero; ++i ) {
        if( m[ rowIndex ][ i ] == 0 )
            zero = true;
    }
    return zero;
}

// This is just a helper function for zeroing a row
void zeroRow( int rowIndex ) {
    for( int i=0; i<n; ++i ) {
        m[ rowIndex ][ i ] = 0;
    }
}

// This function returns whether or not the col contains a zero
bool checkCol( int colIndex ) {
    bool zero = false;
    for( int i=0; i<n && !zero; ++i ) {
        if( m[ i ][ colIndex ] == 0 )
            zero = true;
    }

    return zero;
}

// This is just a helper function for zeroing a col
void zeroCol( int colIndex ) {
    for( int i=0; i<n; ++i ) {
        m[ i ][ colIndex ] = 0;
    }
}

// Just a helper function for printing our matrix to std::out
void printMatrix() {
    std::cout << std::endl;
    for( int y=0; y<n; ++y ) {
        for( int x=0; x<n; ++x ) {
            std::cout << m[y][x] << " ";
        }
        std::cout << std::endl;
    }
    std::cout << std::endl;
}

// Execute!
int main() {
    printMatrix();
    processMatrix();
    printMatrix();
}

2
Bella soluzione, ma tecnicamente stai utilizzando più memoria rispetto ai due booleani consentiti (anche se in pila).
CSL

1
Questo è> 1 passaggio. Se si stampa (rowIndex, i) e (i, colIndex) quando si accede in checkRow e checkCol, si accederà a ciascun elemento più volte.
Draemon,

Draemon: Hai ragione, penso che abbiamo bisogno di una chiara definizione di "single pass" dal creatore dell'enigma. Se in effetti significa che è possibile accedere a ciascun elemento solo una volta, allora abbiamo bisogno di una soluzione diversa.
Adam,

Immagino che il problema originale (che ci è arrivato tramite il gioco del telefono) abbia significato che il problema dovrebbe essere risolto "sul posto", il che significa che non hai un'altra copia della matrice. E le soluzioni più ottimali non hanno nemmeno bisogno di swap temporaneo () come l'archiviazione per l'elaborazione.
Adam,

Inoltre dubito che i vincoli si riferiscano al codice macchina risultante. Significato, il "codice" che ho fornito utilizza solo 2 bool. A seconda di quali ottimizzazioni fa il mio compilatore, l'intera cosa dannata potrebbe essere incorporata o chissà cos'altro. Penso che la mia soluzione sia corretta;)
Adam

4

Non penso sia fattibile. Quando sei sul primo quadrato e il suo valore è 1, non hai modo di sapere quali sono i valori degli altri quadrati nella stessa riga e colonna. Quindi devi controllare quelli e se c'è uno zero, torna al primo quadrato e cambia il suo valore in zero. Ti consiglio di farlo in due passaggi: il primo passaggio raccoglie informazioni su quali righe e colonne devono essere azzerate (le informazioni sono memorizzate in un array, quindi stiamo usando un po 'di memoria aggiuntiva). Il secondo passaggio modifica i valori. So che non è la soluzione che stai cercando, ma penso che sia pratica. I vincoli forniti dall'utente rendono il problema irrisolvibile.


Ho quasi la stessa soluzione (vedi sotto) senza array aggiuntivi. ed è tempo lineare (ma 2 passaggi però)
Piotr Lesnicki il

@Piotr: Sì, il secondo passaggio sembra inevitabile. L'introduzione di array per archiviare le informazioni su righe e colonne che ho proposto rende l'algoritmo più semplice e un po 'più veloce in quanto vi sono meno controlli e cambiamenti di valore. È un compromesso tra conservazione ed efficienza.
Boyan,

3

Posso farlo con due variabili intere e due passaggi (fino a 32 righe e colonne ...)

bool matrix[5][5] = 
{ 
    {1, 0, 1, 1, 0},
    {0, 1, 1, 1, 0},
    {1, 1, 1, 1, 1},
    {1, 0, 1, 1, 1},
    {1, 1, 1, 1, 1}
};

int CompleteRows = ~0;
int CompleteCols = ~0;

// Find the first 0
for (int row = 0; row < 5; ++row)
{
    for (int col = 0; col < 5; ++col)
    {
        CompleteRows &= ~(!matrix[row][col] << row);
        CompleteCols &= ~(!matrix[row][col] << col);
    }
}

for (int row = 0; row < 5; ++row)
    for (int col = 0; col < 5; ++col)
        matrix[row][col] = (CompleteRows & (1 << row)) && (CompleteCols & (1 << col));

Questo è C #? Cosa significa ~?
sciatore

È C ++. ~inverte tutti i bit in una variabile. 0x00000000 diventa 0x00000000. Fondamentalmente inizio con tutti quelli e deseleziono il bit per una riga / colonna quando trovo uno 0. CompleteCols ha i bit 2 e 3 impostati e CompleteRows ha i bit 2 e 4 impostati (basato su 0).
Eclipse,

Quindi basta impostare i bit nella matrice corrispondenti a uno in CompleteCols e CompleteRows.
Eclipse,

3

il problema può essere risolto in un passaggio

salvando la matrice in un array i X j.

1 0 1 1 0
0 1 1 1 0
1 1 1 1 1
1 0 1 1 1 
1 1 1 1 1

one each pass save the values of i and j for an element which is 0 in arrays a and b
when first row is scanned a= 1 b = 2,5
when second row is scanned a=1,2 b= 1,2,5
when third row is scanned no change
when fourth row is scanned a= 1,2,4 and b= 1,2,5
when fifth row is scanned no change .

ora stampa tutti i valori come 0 per i valori di i e j salvati in aeb resto dei valori sono 1 ie (3,3) (3,4) (5,3) e (5,4)


1

Un'altra soluzione che richiede due passaggi è quella di accumulare AND orizzontalmente e verticalmente:

1 0 1 1 0 | 0
0 1 1 1 0 | 0
1 1 1 1 1 | 1
1 0 1 1 1 | 0
1 1 1 1 1 | 1
----------+
0 0 1 1 0    

Pensavo di poter progettare un tale algoritmo usando bit di parità , codici di Hamming o programmazione dinamica , possibilmente usando quei due valori booleani come un numero a 2 bit, ma non ho ancora avuto successo.

Potete ricontrollare la dichiarazione del problema con il vostro ingegnere e farcelo sapere? Se c'è è davvero una soluzione, voglio continuare a intaccando il problema.


1

Mantenere una singola variabile per tenere traccia di quali sono tutte le righe ANDed insieme.

Se una riga è -1 (tutti 1), quindi fare della riga successiva un riferimento a quella variabile

Se una riga è qualsiasi, ma è uno 0. Puoi fare tutto in un passaggio. Pseudo-codice:

foreach (my $row) rows {
     $andproduct = $andproduct & $row;
     if($row != -1) {
        zero out the row
     }  else {
        replace row with a reference to andproduct
     }
}

Dovrebbe farlo, in un unico passaggio, ma qui si presume che N sia abbastanza piccolo da consentire alla CPU di eseguire l'aritmetica su una singola riga, altrimenti sarà necessario scorrere su ogni riga per determinare se è tutto 1s o no, credo. Ma dato che stai chiedendo di algos e di non limitare il mio hardware, vorrei solo iniziare la mia risposta con "Costruisci una CPU che supporti l'aritmetica N-bit ..."

Ecco un esempio di come si può fare in C. Nota: sostengo che i valori e arr presi insieme rappresentano l'array, e p e numproduct sono il mio iteratore e le variabili di prodotto AND utilizzano per implementare il problema. (Avrei potuto fare un giro su arr con aritmetica puntatore per convalidare il mio lavoro, ma una volta era abbastanza!)

int main() {
    int values[] = { -10, 14, -1, -9, -1 }; /* From the problem spec, converted to decimal for my sanity */
    int *arr[5] = { values, values+1, values+2, values+3, values+4 };
    int **p;
    int numproduct = 127;

    for(p = arr; p < arr+5; ++p) {
        numproduct = numproduct & **p;
        if(**p != -1) {
            **p = 0;
        } else {
            *p = &numproduct;
        }
    }

    /* Print our array, this loop is just for show */
    int i;
    for(i = 0; i < 5; ++i) {
        printf("%x\n",*arr[i]);
    }
    return 0;
}

Questo produce 0, 0, 6, 0, 6, che è il risultato per gli input dati.

O in PHP, se la gente pensa che i miei giochi stack in C stiano tradendo (ti suggerisco di no, perché dovrei essere in grado di memorizzare la matrice come preferisco):

<?php

$values = array(-10, 14, -1, -9, -1);
$numproduct = 127;

for($i = 0; $i < 5; ++$i) {
    $numproduct = $numproduct & $values[$i];
    if($values[$i] != -1) {
        $values[$i] = 0;
    } else {
        $values[$i] = &$numproduct;
    }
}

print_r($values);

Mi sto perdendo qualcosa?


Questo non funziona se N è maggiore del numero di bit in un int / long / qualunque cosa quindi non penso che conta.
Draemon,

Inoltre non prenderà le cose se gli 0 sono nella parte inferiore dell'array (provalo con i valori [] = {-1, -9, -1, 14, -10}).
Eclipse,

Draemon, specifica nella mia risposta che senza vincoli hardware come parte della domanda, inizi con "Costruisci una CPU che supporti l'aritmetica N-bit".
Daniel Papasian,

Josh, non lo seguo. Con la soluzione C o PHP e l'array che hai suggerito, ottengo 6 0 6 0 0, che credo sia la risposta corretta.
Daniel Papasian,

@Daniel - Non puoi, perché N non è una costante. Inoltre "costruire un nuovo computer con parole da 1 Mbit non è certo un ragionevole passo algoritmico.
Draemon,

1

Bella sfida. Questa soluzione utilizza solo due booleani creati nello stack, ma i booleani vengono creati più volte nello stack poiché la funzione è ricorsiva.

typedef unsigned short     WORD;
typedef unsigned char      BOOL;
#define true  1
#define false 0
BYTE buffer[5][5] = {
1, 0, 1, 1, 0,
0, 1, 1, 1, 0,
1, 1, 1, 1, 1,
1, 0, 1, 1, 1,
1, 1, 1, 1, 1
};
int scan_to_end(BOOL *h,BOOL *w,WORD N,WORD pos_N)
{
    WORD i;
    for(i=0;i<N;i++)
    {
        if(!buffer[i][pos_N])
            *h=false;
        if(!buffer[pos_N][i])
            *w=false;
    }
    return 0;
}
int set_line(BOOL h,BOOL w,WORD N,WORD pos_N)
{
    WORD i;
    if(!h)
        for(i=0;i<N;i++)
            buffer[i][pos_N] = false;
    if(!w)
        for(i=0;i<N;i++)
            buffer[pos_N][i] = false;
    return 0;
}
int scan(int N,int pos_N)
{
    BOOL h = true;
    BOOL w = true;
    if(pos_N == N)
        return 0;
    // Do single scan
    scan_to_end(&h,&w,N,pos_N);
    // Scan all recursive before changeing data
    scan(N,pos_N+1);
    // Set the result of the scan
    set_line(h,w,N,pos_N);
    return 0;
}
int main(void)
{
    printf("Old matrix\n");
    printf( "%d,%d,%d,%d,%d \n", (WORD)buffer[0][0],(WORD)buffer[0][1],(WORD)buffer[0][2],(WORD)buffer[0][3],(WORD)buffer[0][4]);
    printf( "%d,%d,%d,%d,%d \n", (WORD)buffer[1][0],(WORD)buffer[1][1],(WORD)buffer[1][2],(WORD)buffer[1][3],(WORD)buffer[1][4]);
    printf( "%d,%d,%d,%d,%d \n", (WORD)buffer[2][0],(WORD)buffer[2][1],(WORD)buffer[2][2],(WORD)buffer[2][3],(WORD)buffer[2][4]);
    printf( "%d,%d,%d,%d,%d \n", (WORD)buffer[3][0],(WORD)buffer[3][1],(WORD)buffer[3][2],(WORD)buffer[3][3],(WORD)buffer[3][4]);
    printf( "%d,%d,%d,%d,%d \n", (WORD)buffer[4][0],(WORD)buffer[4][1],(WORD)buffer[4][2],(WORD)buffer[4][3],(WORD)buffer[4][4]);
    scan(5,0);
    printf("New matrix\n");
    printf( "%d,%d,%d,%d,%d \n", (WORD)buffer[0][0],(WORD)buffer[0][1],(WORD)buffer[0][2],(WORD)buffer[0][3],(WORD)buffer[0][4]);
    printf( "%d,%d,%d,%d,%d \n", (WORD)buffer[1][0],(WORD)buffer[1][1],(WORD)buffer[1][2],(WORD)buffer[1][3],(WORD)buffer[1][4]);
    printf( "%d,%d,%d,%d,%d \n", (WORD)buffer[2][0],(WORD)buffer[2][1],(WORD)buffer[2][2],(WORD)buffer[2][3],(WORD)buffer[2][4]);
    printf( "%d,%d,%d,%d,%d \n", (WORD)buffer[3][0],(WORD)buffer[3][1],(WORD)buffer[3][2],(WORD)buffer[3][3],(WORD)buffer[3][4]);
    printf( "%d,%d,%d,%d,%d \n", (WORD)buffer[4][0],(WORD)buffer[4][1],(WORD)buffer[4][2],(WORD)buffer[4][3],(WORD)buffer[4][4]);
    system( "pause" );
    return 0;
}

Questo scansiona in uno schema come:

s,s,s,s,s
s,0,0,0,0
s,0,0,0,0
s,0,0,0,0
s,0,0,0,0


0,s,0,0,0
s,s,s,s,s
0,s,0,0,0
0,s,0,0,0
0,s,0,0,0

e così via

E quindi cambiando i valori in questo modello al ritorno su ciascuna delle funzioni di scansione. (Dal basso verso l'alto):

0,0,0,0,c
0,0,0,0,c
0,0,0,0,c
0,0,0,0,c
c,c,c,c,c


0,0,0,c,0
0,0,0,c,0
0,0,0,c,0
c,c,c,c,c
0,0,0,c,0

e così via


Immagino che questo non sia corretto, dal momento che usi ancora più di due booleani nel tuo stack.
CSL

Come ho triste tipo di due booleani. Questo è il più vicino a cui riesco a pensare alle specifiche fornite. Mi piacerebbe vedere una soluzione reale qui. Se è fattibile.
eaanon01,

Non credo che i requisiti si riferiscano alla crescita dello stack. Penso che questa sia una soluzione perfettamente valida.
Adam,

Anche questo è il mio pensiero. Ma non posso essere sicuro fino a quando qualcun altro pubblicherà una soluzione migliore. Almeno la mia soluzione è compilabile e può essere verificata da chiunque. :) ... Non ho trovato il codice psudo per problemi pratici. Thnx
eaanon01,

1

Va bene, questa è una soluzione

  • utilizza solo un valore extra lungo per l'archiviazione di lavoro.
  • non utilizza alcuna ricorsione.
  • un passaggio di solo N, nemmeno N * N.
  • funzionerà per altri valori di N ma avrà bisogno di nuovi #define.
#include <stdio.h>
#define BIT30 (1<<24)
#define COLMASK 0x108421L
#define ROWMASK 0x1fL
unsigned long long STARTGRID = 
((0x10 | 0x0 | 0x4 | 0x2 | 0x0) << 20) |
((0x00 | 0x8 | 0x4 | 0x2 | 0x0) << 15) |
((0x10 | 0x8 | 0x4 | 0x2 | 0x1) << 10) |
((0x10 | 0x0 | 0x4 | 0x2 | 0x1) << 5) |
((0x10 | 0x8 | 0x4 | 0x2 | 0x1) << 0);


void dumpGrid (char* comment, unsigned long long theGrid) {
    char buffer[1000];
    buffer[0]='\0';
    printf ("\n\n%s\n",comment);
    for (int j=1;j<31; j++) {
        if (j%5!=1)
            printf( "%s%s", ((theGrid & BIT30)==BIT30)? "1" : "0",(((j%5)==0)?"\n" : ",") );    
        theGrid = theGrid << 1;
    }
}

int main (int argc, const char * argv[]) {
    unsigned long long rowgrid = STARTGRID;
    unsigned long long colGrid = rowgrid;

    unsigned long long rowmask = ROWMASK;
    unsigned long long colmask = COLMASK;

    dumpGrid("Initial Grid", rowgrid);
    for (int i=0; i<5; i++) {
        if ((rowgrid & rowmask)== rowmask) rowgrid |= rowmask;
        else rowgrid &= ~rowmask;
        if ((colGrid & colmask) == colmask) colmask |= colmask;
        else colGrid &=  ~colmask;
        rowmask <<= 5;
        colmask <<= 1;
    }
    colGrid &= rowgrid;
    dumpGrid("RESULT Grid", colGrid);
    return 0;
    }

È una buona soluzione per essere sicuri. E suppongo che ogni soluzione qui trascuri almeno uno dei requisiti. Quindi avere una soluzione con un valore massimo consentito per N non è la cosa peggiore al mondo, quindi un bel lavoro su questo :)
Adam,

Limitare N a 8 e affermare che soddisfa il requisito di un passaggio è semplicemente stupido. Questa non è una soluzione generale. Nessuna limitazione è stata dichiarata nella domanda, quindi hai risolto solo un sotto-problema.
Draemon,

ma tutte queste soluzioni hanno un limite su N in un modo o nell'altro.
AnthonyLambert,

Dire che è un passaggio di N è ovviamente completamente sbagliato. Anche solo la lettura del valore di ciascuna posizione nella matrice originale è O (N ^ 2) ed è assolutamente necessario leggere il valore in ciascuna posizione almeno una volta per poter calcolare la soluzione. Anche se memorizzi i valori come bit singoli entro un lungo periodo, l'accesso a ciascun bit sarà O (N ^ 2) perché ci sono O (N ^ 2) bit.
Alderath,

È chiaramente un passaggio il valore RowGrid memorizza l'intera griglia e dopo la prima lettura sarebbe uno dei registri dei processori per l'intero algoritmo se l'ottimizzatore è buono.
AnthonyLambert,

1

In realtà. Se si desidera solo eseguire l'algoritmo e stampare i risultati (ovvero non ripristinarli, è possibile farlo facilmente in un unico passaggio. Il problema si presenta quando si tenta di modificare l'array mentre si esegue l'algoritmo.

Ecco la mia soluzione. Comprende solo ANDing i valori di righe / colonne per un elemento di givein (i, j) e stamparlo.

#include <iostream>
#include "stdlib.h"

void process();

int dim = 5;
bool m[5][5]{{1,0,1,1,1},{0,1,1,0,1},{1,1,1,1,1},{1,1,1,1,1},{0,0,1,1,1}};


int main() {
    process();
    return 0;
}

void process() {
    for(int j = 0; j < dim; j++) {
        for(int i = 0; i < dim; i++) {
            std::cout << (
                          (m[0][j] & m[1][j] & m[2][j] & m[3][j] & m[4][j]) &
                          (m[i][0] & m[i][1] & m[i][2] & m[i][3] & m[i][4])
                          );
        }
        std::cout << std::endl;
    }
}

1

Ho provato a risolvere questo problema in C #.

Ho usato due variabili di loop (i e j) oltre alla matrice effettiva n che rappresentano la sua dimensione

La logica che ho provato è di:

  1. Calcola AND per righe e colonne coinvolti in ciascun quadrato concentrico della matrice
  2. Conservalo nelle sue celle angolari (le ho conservate in ordine antiorario)
  3. Due variabili bool sono utilizzate per conservare i valori di due angoli durante la valutazione di un quadrato particolare.
  4. Questo processo terminerebbe quando il circuito esterno (i) è a metà strada.
  5. Valuta i risultati di altre celle in base alle celle d'angolo (per il resto di i). Salta le celle d'angolo durante questo processo.
  6. Quando raggiungo n, tutte le celle avrebbero il suo risultato tranne le celle d'angolo.
  7. Aggiorna le celle d'angolo. Questa è un'iterazione aggiuntiva alla lunghezza di n / 2 diversa dal vincolo single pass menzionato nel problema.

Codice:

void Evaluate(bool [,] matrix, int n)
{
    bool tempvar1, tempvar2;

    for (var i = 0; i < n; i++)
    {
        tempvar1 = matrix[i, i];
        tempvar2 = matrix[n - i - 1, n - i - 1];

        var j = 0;

        for (j = 0; j < n; j++)
        {
            if ((i < n/2) || (((n % 2) == 1) && (i == n/2) && (j <= i)))
            {
                // store the row and col & results in corner cells of concentric squares
                tempvar1 &= matrix[j, i];
                matrix[i, i] &= matrix[i, j];
                tempvar2 &= matrix[n - j - 1, n - i - 1];
                matrix[n - i - 1, n - i - 1] &= matrix[n - i - 1, n - j - 1];
            }
            else
            {
                // skip corner cells of concentric squares
                if ((j == i) || (j == n - i - 1)) continue;

                // calculate the & values for rest of them
                matrix[i, j] = matrix[i, i] & matrix[n - j - 1, j];
                matrix[n - i - 1, j] = matrix[n - i - 1, n - i - 1] & matrix[n - j - 1, j];

                if ((i == n/2) && ((n % 2) == 1))
                {
                    // if n is odd
                    matrix[i, n - j - 1] = matrix[i, i] & matrix[j, n - j - 1];
                }
            }
        }

        if ((i < n/2) || (((n % 2) == 1) && (i <= n/2)))
        {
            // transfer the values from temp variables to appropriate corner cells of its corresponding square
            matrix[n - i - 1, i] = tempvar1;
            matrix[i, n - i - 1] = tempvar2;
        }
        else if (i == n - 1)
        {
            // update the values of corner cells of each concentric square
            for (j = n/2; j < n; j++)
            {
                tempvar1 = matrix[j, j];
                tempvar2 = matrix[n - j - 1, n - j - 1];

                matrix[j, j] &= matrix[n - j - 1, j];
                matrix[n - j - 1, j] &= tempvar2;

                matrix[n - j - 1, n - j - 1] &= matrix[j, n - j - 1];
                matrix[j, n - j - 1] &= tempvar1;
            }
        }
    }
}

1

One Pass: ho attraversato l'input solo una volta ma ho usato un nuovo array e solo due variabili booleane aggiuntive.

public static void main(String[] args) {

        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        sc.nextLine();

        boolean rowDel = false, colDel = false;
        int arr[][] = new int[n][n];
        int res[][] = new int[n][n];
        int i, j;
        for (i = 0; i < n; i++) {

            for (j = 0; j < n; j++) {
                arr[i][j] = sc.nextInt();
                res[i][j] = arr[i][j];  
            }
        }

        for (i = 0; i < n; i++) {

            for (j = 0; j < n; j++) {
                if (arr[i][j] == 0)
                    colDel = rowDel = true; //See if we have to delete the
                                            //current row and column
                if (rowDel == true){
                    res[i] = new int[n];
                    rowDel = false;
                }
                if(colDel == true){
                    for (int k = 0; k < n; k++) {
                        res[k][j] = 0;
                    }
                    colDel = false;
                }

            }

        }

        for (i = 0; i < n; i++) {

            for (j = 0; j < n; j++) {
                System.out.print(res[i][j]);
            }
            System.out.println();
        }
        sc.close();

    }

0

Sebbene impossibile dato i vincoli, il modo più efficiente in termini di spazio per farlo è attraversare la matrice in modo sovrapposto, alternando riga / colonna, il che renderebbe un modello simile alla posa di mattoni a zig-zag:

-----
|----
||---
|||--
||||-

Usando questo, andresti in ogni riga / colonna, come indicato, e se incontri uno 0 in qualsiasi momento, imposta una variabile booleana e ricomincia da capo quella riga / colonna, impostando le voci su 0 mentre procedi.

Ciò non richiederà ulteriore memoria e utilizzerà solo una variabile booleana. Sfortunatamente, se il bordo "lontano" è impostato su 0, questo è il caso peggiore e percorri l'intero array due volte.


Potrei sbagliarmi, ma sei sicuro che funzioni? Quando esegui la terza colonna, ad esempio, come fai a sapere se il valore nella parte superiore, nella prima riga, era 1 o 0 prima di elaborare la prima riga?
Steve Jessop,

Non lo sai, ma non è nemmeno necessario. Se era uno 0, l'intera colonna deve essere 0. Se il valore nella riga precedente è 1, sai che tutte le righe sopra di essa sono 1 (e lo sono sempre state).
Dave Sherohman,

0

creare una matrice dei risultati e impostare tutti i valori su 1. passare attraverso la matrice dei dati non appena viene rilevato uno 0, impostare la colonna della riga della matrice dei risultati su 0

Alla fine del primo passaggio, la matrice del risultato avrà la risposta corretta.

Sembra piuttosto semplice. C'è un trucco che mi manca? Non ti è consentito utilizzare un set di risultati?

MODIFICARE:

Sembra una funzione F #, ma questo è un po 'barare poiché, anche se stai facendo un singolo passaggio, la funzione può essere ricorsiva.

Sembra che l'intervistatore stia cercando di capire se conosci la programmazione funzionale.


1
L'uso di un set di risultati richiederebbe memoria aggiuntiva.
cdeszaq,

La programmazione funzionale non modifica l'array originale in atto.
Svante,

0

Bene, ho trovato una soluzione a passaggio singolo, sul posto (non ricorsiva) usando 4 bool e 2 contatori loop. Non sono riuscito a ridurlo a 2 bool e 2 ints, ma non sarei sorpreso se fosse possibile. Fa circa 3 letture e 3 scritture di ogni cella, e dovrebbe essere O (N ^ 2) cioè. lineare nella dimensione dell'array.

Mi ci sono volute un paio d'ore per risolvere questo problema - non avrei voluto inventarmelo sotto la pressione di un'intervista! Se ho fatto un booboo sono troppo stanco per individuarlo ...

Ehm ... sto scegliendo di definire "single-pass" come fare uno sweep attraverso la matrice, piuttosto che toccare ogni valore una volta! :-)

#include <stdio.h>
#include <memory.h>

#define SIZE    5

typedef unsigned char u8;

u8 g_Array[ SIZE ][ SIZE ];

void Dump()
{
    for ( int nRow = 0; nRow < SIZE; ++nRow )
    {
        for ( int nColumn = 0; nColumn < SIZE; ++nColumn )
        {
            printf( "%d ", g_Array[ nRow ][ nColumn ] );
        }
        printf( "\n" );
    }
}

void Process()
{
    u8 fCarriedAlpha = true;
    u8 fCarriedBeta = true;
    for ( int nStep = 0; nStep < SIZE; ++nStep )
    {
        u8 fAlpha = (nStep > 0) ? g_Array[ nStep-1 ][ nStep ] : true;
        u8 fBeta = (nStep > 0) ? g_Array[ nStep ][ nStep - 1 ] : true;
        fAlpha &= g_Array[ nStep ][ nStep ];
        fBeta &= g_Array[ nStep ][ nStep ];
        g_Array[ nStep-1 ][ nStep ] = fCarriedBeta;
        g_Array[ nStep ][ nStep-1 ] = fCarriedAlpha;
        for ( int nScan = nStep + 1; nScan < SIZE; ++nScan )
        {
            fBeta &= g_Array[ nStep ][ nScan ];
            if ( nStep > 0 )
            {
                g_Array[ nStep ][ nScan ] &= g_Array[ nStep-1 ][ nScan ];
                g_Array[ nStep-1][ nScan ] = fCarriedBeta;
            }

            fAlpha &= g_Array[ nScan ][ nStep ];
            if ( nStep > 0 )
            {
                g_Array[ nScan ][ nStep ] &= g_Array[ nScan ][ nStep-1 ];
                g_Array[ nScan ][ nStep-1] = fCarriedAlpha;
            }
        }

        g_Array[ nStep ][ nStep ] = fAlpha & fBeta;

        for ( int nScan = nStep - 1; nScan >= 0; --nScan )
        {
            g_Array[ nScan ][ nStep ] &= fAlpha;
            g_Array[ nStep ][ nScan ] &= fBeta;
        }
        fCarriedAlpha = fAlpha;
        fCarriedBeta = fBeta;
    }
}

int main()
{
    memset( g_Array, 1, sizeof(g_Array) );
    g_Array[0][1] = 0;
    g_Array[0][4] = 0;
    g_Array[1][0] = 0;
    g_Array[1][4] = 0;
    g_Array[3][1] = 0;

    printf( "Input:\n" );
    Dump();
    Process();
    printf( "\nOutput:\n" );
    Dump();

    return 0;
}

0

spero che ti piaccia la mia soluzione c # a 1 passaggio

puoi recuperare un elemento con O (1) e hai bisogno solo dello spazio di una riga e una colonna della matrice

bool[][] matrix =
{
    new[] { true, false, true, true, false }, // 10110
    new[] { false, true, true, true, false }, // 01110
    new[] { true, true, true, true, true },   // 11111
    new[] { true, false, true, true, true },  // 10111
    new[] { true, true, true, true, true }    // 11111
};

int n = matrix.Length;
bool[] enabledRows = new bool[n];
bool[] enabledColumns = new bool[n];

for (int i = 0; i < n; i++)
{
    enabledRows[i] = true;
    enabledColumns[i] = true;
}

for (int rowIndex = 0; rowIndex < n; rowIndex++)
{
    for (int columnIndex = 0; columnIndex < n; columnIndex++)
    {
        bool element = matrix[rowIndex][columnIndex];
        enabledRows[rowIndex] &= element;
        enabledColumns[columnIndex] &= element;
    }
}

for (int rowIndex = 0; rowIndex < n; rowIndex++)
{
    for (int columnIndex = 0; columnIndex < n; columnIndex++)
    {
        bool element = enabledRows[rowIndex] & enabledColumns[columnIndex];
        Console.Write(Convert.ToInt32(element));
    }
    Console.WriteLine();
}

/*
    00000
    00000
    00110
    00000
    00110
*/

Penso che l'unico problema potrebbe essere che stai usando due ulteriori array di dati per farlo funzionare. Una delle clausole è di non utilizzare memoria aggiuntiva. Ma carino però! questo è fondamentalmente quello che ho fatto nella mia risposta :)
Kenny Cason,

0

1 passaggio, 2 booleani. Devo solo supporre che gli indici interi nelle iterazioni non contino.

Questa non è una soluzione completa ma non riesco a superare questo punto.

Se solo potessi determinare se uno 0 è uno 0 originale o uno che è stato convertito in uno 0, non dovrei usare -1 e questo funzionerebbe.

La mia uscita è così:

-1  0 -1 -1  0
 0 -1 -1 -1  0
-1 -1  1  1 -1
-1  0 -1 -1 -1
-1 -1  1  1 -1

L'originalità del mio approccio sta usando la prima metà dell'esame di una riga o colonna per determinare se contiene uno 0 e l'ultima metà per impostare i valori - questo viene fatto guardando x e larghezza-x e poi y e altezza -y in ogni iterazione. In base ai risultati della prima metà dell'iterazione, se viene trovato uno 0 nella riga o nella colonna, utilizzo l'ultima metà dell'iterazione per modificare gli 1 in -1.

Ho appena realizzato che questo potrebbe essere fatto con solo 1 booleano che lascia 1 a ...?

Sto postando questo nella speranza che qualcuno possa dire "Ah, fallo e basta ..." (E ci ho passato troppo tempo per non pubblicare.)

Ecco il codice in VB:

Dim D(,) As Integer = {{1, 0, 1, 1, 1}, {0, 1, 1, 0, 1}, {1, 1, 1, 1, 1}, {1, 1, 1, 1, 1}, {0, 0, 1, 1, 1}}

Dim B1, B2 As Boolean

For y As Integer = 0 To UBound(D)

    B1 = True : B2 = True

    For x As Integer = 0 To UBound(D)

        // Scan row for 0's at x and width - x positions. Halfway through I'll konw if there's a 0 in this row.
        //If a 0 is found set my first boolean to false.
        If x <= (Math.Ceiling((UBound(D) + 1) / 2) - 1) Then
            If D(x, y) = 0 Or D(UBound(D) - x, y) = 0 Then B1 = False
        End If

        //If the boolean is false then a 0 in this row was found. Spend the last half of this loop
        //updating the values. This is where I'm stuck. If I change a 1 to a 0 it will cause the column
        //scan to fail. So for now I change to a -1. If there was a way to change to 0 yet later tell if
        //the value had changed this would work.
        If Not B1 Then
            If x >= (Math.Ceiling((UBound(D) + 1) / 2) - 1) Then
                If D(x, y) = 1 Then D(x, y) = -1
                If D(UBound(D) - x, y) = 1 Then D(UBound(D) - x, y) = -1
            End If
        End If

        //These 2 block do the same as the first 2 blocks but I switch x and y to do the column.
        If x <= (Math.Ceiling((UBound(D) + 1) / 2) - 1) Then
            If D(y, x) = 0 Or D(y, UBound(D) - x) = 0 Then B2 = False
        End If

        If Not B2 Then
            If x >= (Math.Ceiling((UBound(D) + 1) / 2) - 1) Then
                If D(y, x) = 1 Then D(y, x) = -1
                If D(y, UBound(D) - x) = 1 Then D(y, UBound(D) - x) = -1
            End If
        End If

    Next
Next

0

Nessuno sta usando i moduli binari? poiché è solo 1 e 0. Possiamo usare i vettori binari.

def set1(M, N):
    '''Set 1/0s on M according to the rules.

    M is a list of N integers. Each integer represents a binary array, e.g.,
    000100'''
    ruler = 2**N-1
    for i,v in enumerate(M):
        ruler = ruler & M[i]
        M[i] = M[i] if M[i]==2**N-1 else 0  # set i-th row to all-0 if not all-1s
    for i,v in enumerate(M):
        if M[i]: M[i] = ruler
    return M

Ecco il test:

M = [ 0b10110,
      0b01110,
      0b11111,
      0b10111,
      0b11111 ]

print "Before..."
for i in M: print "{:0=5b}".format(i)

M = set1(M, len(M))
print "After..."
for i in M: print "{:0=5b}".format(i)

E l'output:

Before...
10110
01110
11111
10111
11111
After...
00000
00000
00110
00000
00110

0

Puoi fare qualcosa del genere per usare un passaggio ma una matrice di input e output:

output(x,y) = col(xy) & row(xy) == 2^n

dove col(xy)sono i bit nella colonna che contiene il punto xy; row(xy)sono i bit nella riga che contiene il punto xy. nè la dimensione della matrice.

Quindi basta scorrere sopra l'ingresso. Forse espandibile per essere più efficiente nello spazio?


0

Una scansione a matrice, due booleani, nessuna ricorsione.

Come evitare il secondo passaggio? Il secondo passaggio è necessario per cancellare le righe o le colonne quando lo zero appare alla loro fine.

Tuttavia, questo problema può essere risolto, poiché quando eseguiamo la scansione della riga #i conosciamo già lo stato della riga # i-1. Quindi, mentre stiamo eseguendo la scansione della riga #i, possiamo cancellare contemporaneamente la riga # i-1 se è necessario.

La stessa soluzione funziona per le colonne, ma è necessario eseguire la scansione di righe e colonne contemporaneamente mentre i dati non vengono modificati dalla successiva iterazione.

Sono necessari due valori booleani per memorizzare lo stato della prima riga e della prima colonna, poiché i loro valori verranno modificati durante l'esecuzione della parte principale dell'algoritmo.

Per evitare di aggiungere altri booleani, stiamo memorizzando il flag "clear" per le righe e le colonne nella prima riga e colonna della matrice.

public void Run()
{
    const int N = 5;

    int[,] m = new int[N, N] 
                {{ 1, 0, 1, 1, 0 },
                { 1, 1, 1, 1, 0 },
                { 1, 1, 1, 1, 1 },
                { 1, 0, 1, 1, 1 },
                { 1, 1, 1, 1, 1 }};

    bool keepFirstRow = (m[0, 0] == 1);
    bool keepFirstColumn = keepFirstRow;

    for (int i = 1; i < N; i++)
    {
        keepFirstRow = keepFirstRow && (m[0, i] == 1);
        keepFirstColumn = keepFirstColumn && (m[i, 0] == 1);
    }

    Print(m); // show initial setup

    m[0, 0] = 1; // to protect first row from clearing by "second pass"

    // "second pass" is performed over i-1 row/column, 
    // so we use one more index just to complete "second pass" over the 
    // last row/column
    for (int i = 1; i <= N; i++)
    {
        for (int j = 1; j <= N; j++)
        {
            // "first pass" - searcing for zeroes in row/column #i
            // when i = N || j == N it is additional pass for clearing 
            // the previous row/column
            // j >= i because cells with j < i may be already modified 
            // by "second pass" part
            if (i < N && j < N && j >= i) 
            {
                m[i, 0] &= m[i, j];
                m[0, j] &= m[i, j];

                m[0, i] &= m[j, i];
                m[j, 0] &= m[j, i];
            }

            // "second pass" - clearing the row/column scanned 
            // in the previous iteration
            if (m[i - 1, 0] == 0 && j < N)
            {
                m[i - 1, j] = 0;
            }

            if (m[0, i - 1] == 0 && j < N)
            {
                m[j, i - 1] = 0;
            }
        }

        Print(m);
    }

    // Clear first row/column if needed
    if (!keepFirstRow || !keepFirstColumn)
    {
        for (int i = 0; i < N; i++)
        {
            if (!keepFirstRow)
            {
                m[0, i] = 0;
            }
            if (!keepFirstColumn)
            {
                m[i, 0] = 0;
            }
        }
    }

    Print(m);

    Console.ReadLine();
}

private static void Print(int[,] m)
{
    for (int i = 0; i < m.GetLength(0); i++)
    {
        for (int j = 0; j < m.GetLength(1); j++)
        {
            Console.Write(" " + m[i, j]);
        }
        Console.WriteLine();
    }
    Console.WriteLine();
}

0

sembra che i seguenti lavori senza requisiti di spazio aggiuntivi:

prima nota che moltiplicando gli elementi della riga per gli elementi della linea in cui si trova un elemento, si ottiene il valore desiderato.

Per non utilizzare alcuno spazio aggiuntivo (non creare una nuova matrice e riempirla ma applicare direttamente le modifiche alla matrice), avvia la parte superiore sinistra della matrice ed esegui il calcolo per qualsiasi matrice ixi (che "inizia" da (0 , 0)) prima di considerare qualsiasi elemento con qualsiasi indice> i.

spero che funzioni (havent testet)


Sembra essere errato. Supponiamo che la riga 0 abbia solo 1 valori. Se il valore finale impostato per (0,0) è 0, in seguito imposterai la riga completa su 0, il che non è necessariamente corretto. In realtà è necessario memorizzare 2 valori per cella per farlo in stile di programmazione dinamica, usando il tuo principio.
Eyal Schneider,

certo, hai ragione. Invece di memorizzare due valori potrei anche usare una terza possibilità, diciamo -1, che sta per celle che sono 1 nella matrice "vecchia" che alla fine verrà sostituita da uno 0. Naturalmente, in questo modo, si deve prendere l'assoluto valori dopo moltiplicazioni. Alla fine, tutti -1 sono sostituiti da 0.
DFF,

0

Questo è TESTATO per N diversi in C ++ ed è:
UN PASSO , DUE BOLLETTE , NESSUNA RICURSIONE , NESSUNA MEMORIA SUPPLEMENTARE , RESA PER ARBITRARMENTE GRANDE N
(Finora nessuna delle soluzioni qui fa TUTTE queste.)

Più specificamente, sto divertendo i contatori a due anelli vanno bene. Ho due const non firmati, che esistono solo anziché essere calcolati ogni volta per leggibilità. L'intervallo del loop esterno è [0, N] e l'intervallo del loop interno è [1, n - 1]. L'istruzione switch è nel ciclo per lo più esiste per mostrare molto chiaramente che è davvero solo un passaggio.

Strategia algoritmo:

Il primo trucco è per noi una riga e una colonna dalla matrice stessa per accumulare il contenuto della matrice, questa memoria diventa disponibile scaricando tutto ciò che abbiamo veramente bisogno di sapere dalla prima riga e colonna in due booleani. Il secondo trucco è quello di ottenere due passaggi da uno, usando la simmetria della matrice secondaria e dei suoi indici.

Sinossi dell'algoritmo:

  • Esegui la scansione della prima riga e memorizza se sono tutti uno in un valore booleano, fai lo stesso per la prima colonna memorizzando il risultato in un secondo valore booleano.
  • Per la matrice secondaria esclusa la prima riga e la prima colonna: scorrere attraverso, da sinistra a destra, dall'alto verso il basso, come si leggerebbe un paragrafo. Dopo aver visitato ciascun elemento, visita anche l'elemento corrispondente che verrebbe visitato se visitassi la matrice secondaria al contrario. Per ogni elemento visitato AND il suo valore nel punto in cui la sua riga attraversa la prima colonna e anche AND il suo valore nel punto in cui la sua colonna attraversa la prima riga.
  • Una volta raggiunto il centro della matrice secondaria, continua a visitare i due elementi contemporaneamente come sopra. Tuttavia ora imposta il valore degli elementi visitati su AND di dove la sua riga attraversa la prima colonna e di dove la sua colonna attraversa la prima riga. Dopodiché, la matrice secondaria è completa.
  • Utilizzare le due variabili booleane calcolate durante l'accattonaggio per impostare la prima riga e la prima colonna sui valori corretti.

Implementazione C ++ templatizzata:

template<unsigned n>
void SidewaysAndRowColumn(int((&m)[n])[n]) {
    bool fcol = m[0][0] ? true : false;
    bool frow = m[0][0] ? true : false;
    for (unsigned d = 0; d <= n; ++d) {
        for (unsigned i = 1; i < n; ++i) {
            switch (d) {
                case 0:
                    frow    = frow && m[d][i];
                    fcol    = fcol && m[i][d];
                    break;
                default:
                {
                    unsigned const rd = n - d;
                    unsigned const ri = n - i;
                    if (d * n + i < rd * n + ri)
                    {
                        m[ d][ 0] &= m[ d][ i];
                        m[ 0][ d] &= m[ i][ d];
                        m[ 0][ i] &= m[ d][ i];
                        m[ i][ 0] &= m[ i][ d];
                        m[rd][ 0] &= m[rd][ri];
                        m[ 0][rd] &= m[ri][rd];
                        m[ 0][ri] &= m[rd][ri];
                        m[ri][ 0] &= m[ri][rd];
                    }
                    else
                    {
                        m[ d][ i] = m[ d][0] & m[0][ i];
                        m[rd][ri] = m[rd][0] & m[0][ri];
                    }
                    break;
                }
                case n:
                    if (!frow)
                        m[0][i] = 0;
                    if (!fcol)
                        m[i][0] = 0;
            };
        }
    }
    m[0][0] = (frow && fcol) ? 1 : 0;
}

0

Ok, mi rendo conto che non è proprio una corrispondenza, ma l'ho preso in un passaggio usando un bool e un byte invece di due bool ... vicino. Inoltre non garantisco l'efficienza, ma questi tipi di domande spesso richiedono soluzioni non ottimali.

private static void doIt(byte[,] matrix)
{
    byte zeroCols = 0;
    bool zeroRow = false;

    for (int row = 0; row <= matrix.GetUpperBound(0); row++)
    {
        zeroRow = false;
        for (int col = 0; col <= matrix.GetUpperBound(1); col++)
        {
            if (matrix[row, col] == 0)
            {

                zeroRow = true;
                zeroCols |= (byte)(Math.Pow(2, col));

                // reset this column in previous rows
                for (int innerRow = 0; innerRow < row; innerRow++)
                {
                    matrix[innerRow, col] = 0;
                }

                // reset the previous columns in this row
                for (int innerCol = 0; innerCol < col; innerCol++)
                {
                    matrix[row, innerCol] = 0;
                }
            }
            else if ((int)(zeroCols & ((byte)Math.Pow(2, col))) > 0)
            {
                matrix[row, col] = 0;
            }

            // Force the row to zero
            if (zeroRow) { matrix[row, col] = 0; }
        }
    }
}

0

Puoi farlo in un solo passaggio - se non conti l'accesso alla matrice in ordine di accesso casuale, il che elimina in primo luogo i vantaggi del passaggio singolo (coerenza cache / larghezza di banda di memoria).

[modifica: eliminata la soluzione semplice ma errata]

Dovresti ottenere prestazioni migliori rispetto a qualsiasi metodo a passaggio singolo eseguendolo in due passaggi: uno per accumulare informazioni su riga / colonna e uno per applicarlo. L'array (nell'ordine delle righe principali) è accessibile in modo coerente; per array che superano le dimensioni della cache (ma le cui righe possono rientrare nella cache), i dati devono essere letti dalla memoria due volte e archiviati una volta:

void fixmatrix2(int M[][], int rows, int cols) {
    bool clearZeroRow= false;
    bool clearZeroCol= false;
    for(int j=0; j < cols; ++j) {
        if( ! M[0][j] ) {
            clearZeroRow= true;
        }
    }
    for(int i=1; i < rows; ++i) { // scan/accumulate pass
        if( ! M[i][0] ) {
            clearZeroCol= true;
        }
        for(int j=1; j < cols; ++j) {
            if( ! M[i][j] ) {
                M[0][j]= 0;
                M[i][0]= 0;
            }
        }
    }
    for(int i=1; i < rows; ++i) { // update pass
        if( M[i][0] ) {
            for(int j=0; j < cols; ++j) {
                if( ! M[j][0] ) {
                    M[i][j]= 0;
                }
            }
        } else {
            for(int j=0; j < cols; ++j) {
                M[i][j]= 0;
            }
        }
        if(clearZeroCol) {
            M[i][0]= 0;
        }
    }
    if(clearZeroRow) {
        for(int j=0; j < cols; ++j) {
            M[0][j]= 0;
        }
    }
}

0

La soluzione più semplice che mi viene in mente è incollata di seguito. La logica è registrare quale riga e colonna impostare zero durante l'iterazione.

import java.util.HashSet;
import java.util.Set;

public class MatrixExamples {
    public static void zeroOut(int[][] myArray) {
        Set<Integer> rowsToZero = new HashSet<>();
        Set<Integer> columnsToZero = new HashSet<>();

        for (int i = 0; i < myArray.length; i++) { 
            for (int j = 0; j < myArray.length; j++) {
                if (myArray[i][j] == 0) {
                    rowsToZero.add(i);
                    columnsToZero.add(j);
                }
            }
        }

        for (int i : rowsToZero) {
            for (int j = 0; j < myArray.length; j++) {
                myArray[i][j] = 0;
            }
        }

        for (int i : columnsToZero) {
            for (int j = 0; j < myArray.length; j++) {
                myArray[j][i] = 0;
            }
        }

        for (int i = 0; i < myArray.length; i++) { // record which rows and                                             // columns will be zeroed
            for (int j = 0; j < myArray.length; j++) {
                System.out.print(myArray[i][j] + ",");
            if(j == myArray.length-1)
                System.out.println();
            }
        }

    }

    public static void main(String[] args) {
        int[][] a = { { 1, 0, 1, 1, 0 }, { 0, 1, 1, 1, 0 }, { 1, 1, 1, 1, 1 },
                { 1, 0, 1, 1, 1 }, { 1, 1, 1, 1, 1 } };
        zeroOut(a);
    }
}

0

Ecco la mia implementazione di Ruby con il test incluso, questo richiederebbe spazio O (MN). Se vogliamo un aggiornamento in tempo reale (ad esempio per mostrare i risultati quando troviamo gli zeri piuttosto che attendere il primo ciclo di ricerca degli zeri), possiamo semplicemente creare un'altra variabile di classe come @outpute ogni volta che troviamo uno zero che aggiorniamo @outpute non @input.

require "spec_helper"


class Matrix
    def initialize(input)
        @input  = input
        @zeros  = []
    end

    def solve
        @input.each_with_index do |row, i|          
            row.each_with_index do |element, j|                             
                @zeros << [i,j] if element == 0
            end
        end

        @zeros.each do |x,y|
            set_h_zero(x)
            set_v_zero(y)
        end

        @input
    end


    private 

    def set_h_zero(row)     
        @input[row].map!{0}     
    end

    def set_v_zero(col)
        @input.size.times do |r|
            @input[r][col] = 0
        end
    end
end


describe "Matrix" do
  it "Should set the row and column of Zero to Zeros" do
    input =  [[1, 3, 4, 9, 0], 
              [0, 3, 5, 0, 8], 
              [1, 9, 6, 1, 9], 
              [8, 3, 2, 0, 3]]

    expected = [[0, 0, 0, 0, 0],
                [0, 0, 0, 0, 0],
                [0, 9, 6, 0, 0],
                [0, 0, 0, 0, 0]]

    matrix = Matrix.new(input)

    expect(matrix.solve).to eq(expected)
  end
end

0

Il codice seguente crea una matrice di dimensioni m, n. Decidi innanzitutto le dimensioni della matrice. Volevo riempire la matrice [m] [n] in modo casuale con numeri tra 0..10. Quindi crea un'altra matrice delle stesse dimensioni e riempila con -1s (matrice finale). Quindi scorrere la matrice iniziale per vedere se si colpisce 0. Quando si preme sulla posizione (x, y), andare alla matrice finale e riempire la riga x con 0s e la colonna y con 0s. Alla fine leggi la matrice finale, se il valore è -1 (valore originale) copia il valore nella stessa posizione della matrice iniziale in final.

public static void main(String[] args) {
    int m = 5;
    int n = 4;
    int[][] matrixInitial = initMatrix(m, n); // 5x4 matrix init randomly
    int[][] matrixFinal = matrixNull(matrixInitial, m, n); 
    for (int i = 0; i < m; i++) {
        System.out.println(Arrays.toString(matrixFinal[i]));
    }
}

public static int[][] matrixNull(int[][] matrixInitial, int m, int n) {
    int[][] matrixFinal = initFinal(m, n); // create a matrix with mxn and init it with all -1
    for (int i = 0; i < m; i++) { // iterate in initial matrix
        for (int j = 0; j < n; j++) {
            if(matrixInitial[i][j] == 0){ // if a value is 0 make rows and columns 0
                makeZeroX(matrixFinal, i, j, m, n); 
            }
        }
    }

    for (int i = 0; i < m; i++) { // if value is -1 (original) copy from initial
        for (int j = 0; j < n; j++) {
            if(matrixFinal[i][j] == -1) {
                matrixFinal[i][j] = matrixInitial[i][j];
            }
        }
    }
    return matrixFinal;
}

private static void makeZeroX(int[][] matrixFinal, int x, int y, int m, int n) {
        for (int j = 0; j < n; j++) { // make all row 0
            matrixFinal[x][j] = 0;
        }
        for(int i = 0; i < m; i++) { // make all column 0
            matrixFinal[i][y] = 0; 
        }
}

private static int[][] initMatrix(int m, int n) {

    int[][] matrix = new int[m][n];
    for (int i = 0; i < m; i++) {
        for (int j = 0; j < n; j++) {
            Random rn = new Random();
            int random = rn.nextInt(10);
            matrix[i][j] = random;
        }
    }

    for (int i = 0; i < m; i++) {
        System.out.println(Arrays.toString(matrix[i]));
    }
    System.out.println("******");
    return matrix;
}

private static int[][] initFinal(int m, int n) {

    int[][] matrix = new int[m][n];
    for (int i = 0; i < m; i++) {
        for (int j = 0; j < n; j++) {
            matrix[i][j] = -1;
        }
    }
    return matrix;
}

// another approach
/**
 * @param matrixInitial
 * @param m
 * @param n
 * @return
 */
private static int[][] matrixNullNew(int[][] matrixInitial, int m, int n) {
    List<Integer> zeroRowList = new ArrayList<>(); // Store rows with 0
    List<Integer> zeroColumnList = new ArrayList<>(); // Store columns with 0
    for (int i = 0; i < m; i++) { // read through the matrix when you hit 0 add the column to zeroColumnList and add
                                  // the row to zeroRowList
        for (int j = 0; j < n; j++) {
            if (matrixInitial[i][j] == 0) {
                if (!zeroRowList.contains(i)) {
                    zeroRowList.add(i);
                }
                if (!zeroColumnList.contains(j)) {
                    zeroColumnList.add(j);
                }
            }
        }
    }

    for (int a = 0; a < m; a++) {
        if (zeroRowList.contains(a)) { // if the row has 0
            for (int b = 0; b < n; b++) {
                matrixInitial[a][b] = 0; // replace all row with zero
            }
        }
    }

    for (int b = 0; b < n; b++) {
        if (zeroColumnList.contains(b)) { // if the column has 0
            for (int a = 0; a < m; a++) {
                matrixInitial[a][b] = 0; // replace all column with zero
            }
        }
    }
    return matrixInitial;
}

Non fornisci alcuna spiegazione o contesto al codice che hai pubblicato.
Aaron,

Spero che ora vada meglio. Grazie per l'avviso. Vorrei spiegare di più, se non è chiaro per te.
user3743369,

0

ecco la mia soluzione. Come puoi vedere dal codice, data una matrice M * N, imposta l'intera riga su zero una volta ispezionato uno zero in quella riga. La complessità temporale della mia soluzione è O (M * N). Sto condividendo l'intera classe che ha un array popolato statico per i test e un metodo di array display per vedere il risultato nella console.

public class EntireRowSetToZero {
    static int arr[][] = new int[3][4];
    static {

    arr[0][0] = 1;
    arr[0][1] = 9;
    arr[0][2] = 2;
    arr[0][3] = 2;

    arr[1][0] = 1;
    arr[1][1] = 5;
    arr[1][2] = 88;
    arr[1][3] = 7;

    arr[2][0] = 0;
    arr[2][1] = 8;
    arr[2][2] = 4;
    arr[2][3] = 4;
}

public static void main(String[] args) {
    displayArr(EntireRowSetToZero.arr, 3, 4);
    setRowToZero(EntireRowSetToZero.arr);
    System.out.println("--------------");
    displayArr(EntireRowSetToZero.arr, 3, 4);


}

static int[][] setRowToZero(int[][] arr) {
    for (int i = 0; i < arr.length; i++) {
        for (int j = 0; j < arr[i].length; j++) {
            if(arr[i][j]==0){
                arr[i]=new int[arr[i].length];
            }
        }

    }
    return arr;
}

static void displayArr(int[][] arr, int n, int k) {

    for (int i = 0; i < n; i++) {

        for (int j = 0; j < k; j++) {
            System.out.print(arr[i][j] + " ");
        }
        System.out.println("");
    }

}

}

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.