Atur setiap sel dalam matriks ke 0 jika baris atau kolom itu berisi 0

152

Diberi matriks NxN dengan 0s dan 1s. Atur setiap baris yang berisi a 0untuk semua 0dan atur setiap kolom yang berisi a 0untuk semua 0.

Sebagai contoh

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

hasil dalam

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

Seorang Insinyur Microsoft mengatakan kepada saya bahwa ada solusi yang tidak melibatkan memori tambahan, hanya dua variabel boolean dan satu pass, jadi saya mencari jawaban itu.

BTW, bayangkan itu adalah matriks bit, oleh karena itu hanya 1s dan 0s yang diizinkan berada dalam matriks.

akun lama-jaircazarin
sumber
1
Hah? Apa itu "setiap kali Anda bertemu"? Dalam urutan apa Anda menemukan elemen-elemen dalam matriks? Dan jika Anda menemukan semua bit, bukankah Anda akan mendapatkan semua 0s?
ShreevatsaR
Nah, urutan di mana Anda memutuskan untuk menemukan elemen adalah keputusan Anda, masalahnya adalah Anda hanya perlu menetapkan elemen yang tepat. Jika Anda menemukan semua bit yang diatur ke 0, ya matriks akan tetap diisi dengan nol.
jaircazarin-old-akun
Apa itu "elemen yang tepat"? Apakah Anda diberi dua matriks, satu matriks "sumber" dan satu matriks "target" dan Anda harus memutuskan di mana untuk "menemukan" elemen-elemen sehingga mendapatkan matriks "target"?
ShreevatsaR
1
Saya pikir Anda salah dengar sesuatu untuk berpikir '1 pass'. Hal ini dapat dilakukan secara linear dalam 2 operan, tanpa memori tambahan, hanya 2 boolean ;-) Jadi saya sangat berasumsi bahwa itu adalah solusi yang ia maksud (lihat di bawah)
Piotr Lesnicki
1
Bisakah Anda memeriksa ulang dengan teman Anda jika deskripsi masalah memang benar? Saya pikir saya bisa melakukan ini dengan kode Hamming atau bit paritas, tapi sejauh ini saya tidak berhasil, dan masalah terus menjepit di kepala saya. :)
csl

Jawaban:

96

Ok, jadi saya lelah karena ini jam 3 pagi di sini, tapi saya punya percobaan pertama dengan tepat 2 melewati setiap angka dalam matriks, jadi di O (NxN) dan linear dalam ukuran matriks.

Saya menggunakan kolom pertama dan baris pertama sebagai penanda untuk mengetahui di mana baris / cols hanya dengan 1's. Lalu, ada 2 variabel l dan c yang perlu diingat jika baris / kolom pertama adalah semua 1 juga. Jadi pass pertama mengatur marker dan me-reset sisanya ke 0's.

Lewat kedua menetapkan 1 di tempat baris dan col mana ditandai 1, dan me-reset baris 1 / col tergantung pada l dan c.

Saya sangat ragu bahwa saya dapat dilakukan dalam 1 pass karena kotak pada awalnya tergantung pada kotak pada akhirnya. Mungkin pass kedua saya dapat dibuat lebih efisien ...

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)
Piotr Lesnicki
sumber
Satu masalah di sini adalah jika n> sizeof (c) maka itu rusak. Untuk memperluas ini agar berfungsi dalam kasus umum n, Anda perlu mengukur bidang bit Anda secara dinamis yang saya pikir akan melanggar batasan yang diberikan oleh masalah.
Adam
Tidak, c bukan bitfield, itu hanya bool. & = Bukan op bitwise (well, itu, tetapi pada nilai 1-bit), itu ada karena c memberitahu Anda apakah kolom pertama adalah semua 1 (benar) atau berisi 0 (salah).
Steve Jessop
2
Gagal jika baris teratas adalah [0,1,1,1 ...] Perbaikan bug saya adalah menginisialisasi l ke m [0] [0] daripada 1
paperhorse
memang l = 1 untuk i dalam range (1, N): l & = m [0] [i] harus l = 1 untuk i dalam range (N): l & = m [0] [i]
Kristof Neirynck
1
BTW, saya percaya bahwa kondisi pada pass kedua harus seperti: if m [i] [0] | m [0] [j]:
jaircazarin-old-akun
16

Ini tidak dapat dilakukan dalam satu pass karena bit tunggal memiliki efek pada bit sebelum dan sesudahnya dalam pemesanan apa pun. TKI Apa pun perintah yang Anda lewati array, Anda mungkin akan menemukan 0 yang berarti Anda harus kembali dan mengubah 1 sebelumnya ke 0.

Memperbarui

Orang-orang tampaknya berpikir bahwa dengan membatasi N pada nilai tetap (katakanlah 8) Anda dapat menyelesaikan ini dengan satu pass. Ya itu a) melewatkan poin dan b) bukan pertanyaan awal. Saya tidak akan memposting pertanyaan tentang pengurutan dan mengharapkan jawaban yang dimulai "dengan asumsi Anda hanya ingin mengurutkan 8 hal ...".

Yang mengatakan, itu adalah pendekatan yang masuk akal jika Anda tahu bahwa N sebenarnya terbatas pada 8. Jawaban saya di atas menjawab pertanyaan awal yang tidak memiliki batasan seperti itu.

Draemon
sumber
Itu tidak dapat dilakukan dalam satu pass tanpa memori tambahan. Hal ini dapat dilakukan dalam satu laluan jika ada matriks NxN lain untuk menyimpan hasil. Demikian juga, dengan beberapa bit bengkok dan dua lintasan dapat dilakukan tanpa memori tambahan.
paxos1977
2
Anda masih tidak dapat melakukannya dalam satu pass bahkan jika Anda menggunakan matriks sementara, atau ada sesuatu yang aneh yang tidak saya dapatkan di sini. Anda memerlukan satu pass untuk menyimpulkan informasi baris / kolom, dan satu pass untuk mengatur semuanya.
Lasse V. Karlsen
Saya memecahkan masalah ini dengan mengakui bahwa hanya ada satu nilai non-nol yang unik yang mungkin per baris, dan hanya menugaskannya dengan referensi.
Daniel Papasian
@ceretullis, lassevk: Saya masih berpikir itu tidak dapat dilakukan dalam satu pass. Melewati matriks kedua harus dihitung - jika tidak, Anda bisa menyalin matriks dalam satu pass, dan bekerja dengan salinan sesuai keinginan Anda. @Daniel Papasian: Solusi Anda tidak mengukur di mana N> #bits di int / long / apapun
Draemon
Draemon, teknik ini berskala baik, itu hanya matematika - Anda dapat membangun perangkat keras yang melakukannya, atau Anda dapat menggunakan teknik perangkat lunak untuk memanipulasi angka yang lebih besar dari ukuran kata Anda. Tidak melanggar kendala masalah, IMHO
Daniel Papasian
10

Jadi ide saya adalah menggunakan nilai-nilai di baris / kolom terakhir sebagai bendera untuk menunjukkan apakah semua nilai di kolom / baris yang sesuai adalah 1s.

Menggunakan pemindaian Zig Zag melalui seluruh matriks KECUALI baris / kolom terakhir. Di setiap elemen, Anda menetapkan nilai di baris / kolom terakhir ke logika AND dari dirinya sendiri dengan nilai di elemen saat ini. Dengan kata lain, jika Anda menekan 0, baris / kolom terakhir akan diatur ke 0. Jika Anda menjadi 1, nilai di baris / kolom terakhir akan menjadi 1 hanya jika sudah 1. Bagaimanapun mengatur elemen saat ini ke 0.

Setelah selesai, baris / kolom akhir Anda harus memiliki 1s jika kolom / baris terkait diisi dengan 1s.

Lakukan pemindaian linear melalui baris dan kolom terakhir dan cari 1s. Tetapkan 1s dalam elemen yang sesuai dalam tubuh matriks di mana baris terakhir dan kolom keduanya 1s.

Pengkodean akan sulit untuk menghindari kesalahan satu per satu dll, tetapi itu harus bekerja dalam satu pass.

Alastair
sumber
Sangat bagus ... Saya berpikir pada baris yang sama, tetapi tidak menggunakan baris terakhir / kolom untuk menyimpan informasi itu, jadi saya terjebak dengan memori tambahan untuk sepasang array Nx1.
Dave Sherohman
1
Itu terlihat seperti dua lintasan bagi saya - satu lintasan adalah pemindaian zig-zag, yang kedua adalah "Set 1s dalam elemen yang sesuai dalam tubuh matriks di mana baris dan kolom terakhir adalah 1s".
Adam Rosenfield
Pemindaian zig-zag (yang ditunjukkan oleh seseorang kepada saya tidak sepenuhnya diperlukan) melintasi semua TETAPI baris / kolom terakhir. Jadi pemindaian kolom akhir / baris tidak menduplikasi elemen yang telah dipindai sebelumnya. Karenanya satu lulus. Dengan kata lain itu O (N ^ 2) untuk matriks N * N.
Alastair
6

Saya punya solusi di sini, ini berjalan dalam sekali jalan, dan melakukan semua pemrosesan "di tempat" tanpa memori tambahan (simpan untuk menumbuhkan tumpukan).

Ini menggunakan rekursi untuk menunda penulisan nol yang tentu saja akan menghancurkan matriks untuk baris dan cols lainnya:

#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();
}
Adam
sumber
2
Solusi yang bagus, tetapi Anda, secara teknis, menggunakan lebih banyak memori daripada dua boolean yang diizinkan (meskipun di stack).
csl
1
Ini> 1 pass. Jika Anda mencetak (rowIndex, i) dan (i, colIndex) ketika mereka diakses di checkRow dan checkCol Anda akan melihat bahwa setiap elemen diakses beberapa kali.
Draemon
Draemon: Anda benar, saya pikir kita perlu definisi yang jelas tentang "pass tunggal" dari pembuat teka-teki. Jika dia benar-benar berarti bahwa setiap elemen hanya dapat diakses sekali, maka kita membutuhkan solusi yang berbeda.
Adam
Saya membayangkan masalah asli (yang datang kepada kami melalui permainan telepon) berarti masalah tersebut harus diselesaikan "di tempat" yang berarti Anda tidak memiliki salinan lain dari matriks. Dan solusi yang lebih optimal bahkan tidak perlu swap sementara () seperti penyimpanan untuk diproses.
Adam
Juga saya agak meragukan kendala mengacu pada kode mesin yang dihasilkan. Artinya, "kode" yang saya berikan hanya menggunakan 2 bools. Bergantung pada pengoptimalan yang dilakukan oleh kompiler saya, seluruh masalah bisa diuraikan atau siapa yang tahu apa lagi. Saya pikir solusi saya sudah benar;)
Adam
4

Saya tidak berpikir itu bisa dilakukan. Saat Anda berada di kotak pertama dan nilainya 1, Anda tidak memiliki cara untuk mengetahui apa nilai kotak lainnya di baris dan kolom yang sama. Jadi, Anda harus memeriksa dan jika ada nol, kembali ke kuadrat pertama dan ubah nilainya menjadi nol. Saya akan merekomendasikan melakukannya dalam dua lintasan - lintasan pertama mengumpulkan informasi tentang baris dan kolom mana yang harus di-nolkan (informasi disimpan dalam sebuah array, jadi kami menggunakan memori tambahan). Lewat kedua mengubah nilai. Saya tahu itu bukan solusi yang Anda cari, tetapi saya pikir itu solusi yang praktis. Batasan yang diberikan oleh Anda membuat masalah tidak dapat dipecahkan.

Boyan
sumber
Saya memiliki solusi yang hampir sama (lihat di bawah) tanpa array tambahan. dan ini adalah waktu linier (tapi 2 berlalu)
Piotr Lesnicki
@Piotr: Ya, pass kedua tampaknya tidak dapat dihindari. Pengenalan array untuk menyimpan informasi baris dan kolom yang saya usulkan membuat algoritma lebih mudah dan sedikit lebih cepat karena ada lebih sedikit pengecekan dan perubahan nilai. Ini adalah pertukaran antara penyimpanan dan efisiensi.
Boyan
3

Saya bisa melakukannya dengan dua variabel integer dan dua lintasan (hingga 32 baris dan kolom ...)

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));
Gerhana
sumber
Apakah ini C #? Apa artinya ~?
pemain ski
Ini C ++. ~membalikkan semua bit dalam suatu variabel. 0x00000000 menjadi 0x00000000. Saya pada dasarnya memulai dengan semua yang ada, dan menghapus bit untuk baris / kolom ketika saya menemukan 0. CompleteCols memiliki bit 2 dan 3 set, dan CompleteRows memiliki bit 2 dan 4 set (0 based).
Eclipse
Kemudian Anda hanya mengatur bit dalam matriks yang sesuai dengan yang ada di CompleteCols dan CompleteRows.
Eclipse
3

masalahnya bisa diselesaikan dalam satu pass

menyimpan matriks dalam 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 .

sekarang cetak semua nilai sebagai 0 untuk nilai i dan j yang disimpan dalam a dan b sisanya dari nilai tersebut yaitu 1 yaitu (3,3) (3,4) (5,3) dan (5,4)

siddharth
sumber
1

Solusi lain yang membutuhkan dua lintasan, adalah mengakumulasi AND secara horizontal dan vertikal:

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    

Saya pikir saya bisa merancang algoritma seperti itu menggunakan bit paritas , kode Hamming atau pemrograman dinamis , mungkin menggunakan dua boolean sebagai angka 2-bit, tapi saya belum berhasil.

Bisakah Anda memeriksa kembali pernyataan masalah dengan insinyur Anda dan beri tahu kami? Jika ada yang memang solusi, aku ingin terus chipping jauh di masalah.

csl
sumber
1

Simpan satu variabel untuk melacak semua baris ANDed bersama.

Jika satu baris adalah -1 (semua 1s), maka buat baris berikutnya sebagai referensi ke variabel itu

Jika satu baris adalah sesuatu tetapi, itu adalah 0. Anda dapat melakukan semuanya dalam satu pass. Kode psuedo:

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

Itu harus melakukannya, dalam sekali lulus - tetapi ada asumsi di sini bahwa N cukup kecil untuk CPU untuk melakukan aritmatika pada satu baris, jika tidak, Anda akan perlu untuk mengulang setiap baris untuk menentukan apakah itu semua 1s atau tidak, saya percaya. Tetapi mengingat Anda bertanya tentang algos dan tidak membatasi perangkat keras saya, saya hanya akan memulai jawaban saya dengan "Bangun CPU yang mendukung aritmatika N-bit ..."

Inilah salah satu contoh bagaimana hal itu dapat dilakukan dalam C. Catatan saya berpendapat bahwa nilai dan arr yang diambil bersama-sama mewakili array, dan p dan numproduct adalah iterator saya dan variabel produk AND digunakan untuk mengimplementasikan masalah. (Saya bisa mengulangi arr dengan pointer aritmatika untuk memvalidasi pekerjaan saya, tetapi sekali sudah cukup!)

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

Ini menghasilkan 0, 0, 6, 0, 6, yang merupakan hasil untuk input yang diberikan.

Atau di PHP, jika orang berpikir bahwa permainan tumpukan saya di C curang (saya sarankan Anda tidak melakukannya, karena saya harus dapat menyimpan matriks mana pun yang saya inginkan):

<?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);

Apakah saya melewatkan sesuatu?

Daniel Papasian
sumber
Ini tidak berfungsi jika N lebih besar dari jumlah bit di int / long / apapun jadi saya tidak berpikir itu penting.
Draemon
Itu juga tidak akan menangkap hal-hal jika 0 berada di bagian bawah array (coba dengan nilai [] = {-1, -9, -1, 14, -10}).
Eclipse
Draemon, saya menentukan dalam jawaban saya bahwa tanpa kendala perangkat keras sebagai bagian dari pertanyaan, Anda mulai dengan "Membangun CPU yang mendukung aritmatika N-bit."
Daniel Papasian
Josh, saya tidak mengikuti. Baik dengan solusi C atau PHP dan array yang Anda sarankan, saya mendapatkan 6 0 6 0 0, yang saya percaya adalah jawaban yang benar.
Daniel Papasian
@Aniel - Anda tidak bisa, karena N tidak konstan. Selain itu "bangun komputer baru dengan kata-kata 1Mbit bukanlah langkah algoritmik yang masuk akal.
Draemon
1

Tantangan yang bagus. Solusi ini menggunakan hanya dua boolean yang dibuat di stack, tetapi boolean dibuat beberapa kali di stack karena fungsinya bersifat rekursif.

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

Ini memindai dalam pola seperti:

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

dan seterusnya

Dan kemudian mengubah nilai-nilai dalam pola ini setelah kembali pada masing-masing fungsi pemindaian. (Bawah ke atas):

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

dan seterusnya

eaanon01
sumber
Saya kira ini tidak benar, karena Anda masih menggunakan lebih dari dua boolean di tumpukan Anda.
csl
Seperti aku sedih dua boolean. Ini adalah yang paling dekat yang bisa saya pikirkan dengan spesifikasi yang dia berikan. Saya ingin melihat solusi aktual di sini. Jika itu fesable.
eaanon01
Saya tidak berpikir persyaratan mengacu pada menumbuhkan tumpukan. Saya pikir ini adalah solusi yang sangat valid.
Adam
Itu juga milikku. Tapi saya tidak yakin sampai orang lain memposting solusi yang lebih baik. Setidaknya solusi saya dapat dikompilasi dan dapat diverifikasi oleh siapa saja. :) ... Saya tidak menemukan kode psudo untuk masalah praktis. Thnx
eaanon01
1

Oke ini solusinya

  • hanya menggunakan satu nilai ekstra panjang untuk penyimpanan yang berfungsi.
  • tidak menggunakan rekursi.
  • satu pass hanya N, bahkan N * N.
  • akan bekerja untuk nilai N lainnya tetapi akan membutuhkan #defines baru.
#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;
    }
AnthonyLambert
sumber
Ini adalah solusi yang bagus untuk dipastikan. Dan saya kira setiap solusi di sini mengabaikan setidaknya satu persyaratan. Jadi memiliki solusi dengan nilai maksimum yang diizinkan untuk N bukan hal terburuk di dunia, pekerjaan yang begitu bagus :)
Adam
Membatasi N hingga 8 dan mengklaim ini memenuhi persyaratan satu lulus, benar-benar bodoh. Ini bukan solusi umum. Tidak ada batasan ukuran N yang disebutkan dalam pertanyaan, jadi Anda hanya memecahkan sub-masalah.
Draemon
tetapi semua solusi ini memiliki batas N dalam satu atau lain cara.
AnthonyLambert
Mengatakan bahwa ini adalah satu operan N jelas sangat salah. Bahkan hanya membaca nilai setiap posisi dalam matriks asli adalah O (N ^ 2) dan yang paling penting adalah perlu membaca nilai di setiap posisi setidaknya sekali untuk dapat menghitung solusi. Bahkan jika Anda menyimpan nilai sebagai bit tunggal dalam waktu yang lama, mengakses setiap bit akan menjadi O (N ^ 2) karena ada bit O (N ^ 2).
Alderath
Jelas satu lulus nilai RowGrid menyimpan seluruh grid dan setelah membaca 1 akan menjadi salah satu register prosesor untuk seluruh algoritma jika optimizer bagus.
AnthonyLambert
1

Sebenarnya. Jika Anda hanya ingin menjalankan algoritme dan mencetak hasilnya (yaitu tidak mengembalikannya, maka ini dapat dengan mudah dilakukan dalam satu langkah. Masalahnya muncul ketika Anda mencoba memodifikasi array saat Anda menjalankan algoritma.

Inilah solusi saya. Ini hanya melibatkan ANDing nilai baris / kolom untuk elemen givein (i, j) dan mencetaknya.

#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;
    }
}
Kenny Cason
sumber
1

Saya mencoba menyelesaikan masalah ini dalam C #.

Saya telah menggunakan dua variabel loop (i dan j) selain dari matriks aktual dan n yang mewakili dimensinya

Logika yang saya coba adalah:

  1. Hitung DAN untuk baris dan kolom yang terlibat dalam setiap kotak konsentris dari matriks
  2. Simpan di sel-sel sudutnya (Saya telah menyimpannya dalam urutan anti-jarum jam)
  3. Dua variabel bool digunakan untuk mempertahankan nilai dua sudut saat mengevaluasi kuadrat tertentu.
  4. Proses ini akan berakhir ketika loop luar (i) berada di tengah jalan.
  5. Mengevaluasi hasil sel lain berdasarkan sel sudut (untuk sisa i). Lewati sel sudut selama proses ini.
  6. Ketika saya mencapai n, semua sel akan memiliki hasilnya kecuali untuk sel sudut.
  7. Perbarui sel sudut. Ini adalah iterasi tambahan untuk panjang n / 2 selain batasan single pass yang disebutkan dalam masalah.

Kode:

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;
            }
        }
    }
}
BK
sumber
1

One Pass - Saya telah melewati input hanya sekali tetapi menggunakan array baru dan hanya dua variabel Boolean tambahan.

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();

    }
RahulDeep Attri
sumber
0

Meskipun tidak mungkin mengingat kendala, cara paling efisien ruang untuk melakukannya adalah dengan melintasi matriks dengan cara baris / kolom bergantian yang tumpang tindih, yang akan membuat pola yang mirip dengan meletakkan batu bata dalam mode zig-zag:

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

Dengan menggunakan ini, Anda akan pergi di setiap baris / kolom, seperti yang ditunjukkan, dan jika Anda menemukan 0 setiap saat, atur variabel boolean, dan berjalan kembali baris / kolom itu, atur entri ke 0 saat Anda pergi.

Ini tidak memerlukan memori tambahan, dan hanya akan menggunakan satu variabel boolean. Sayangnya, jika tepi "jauh" diatur ke semua menjadi 0, itu adalah kasus terburuk dan Anda berjalan di seluruh array dua kali.

cdeszaq
sumber
Saya bisa saja salah, tetapi apakah Anda yakin ini berhasil? Saat Anda melakukan kolom ke-3, katakanlah, bagaimana Anda tahu apakah nilai di atasnya, di baris pertama, adalah 1 atau 0 sebelum Anda memproses baris pertama?
Steve Jessop
Anda tidak tahu, tetapi Anda juga tidak perlu. Jika itu adalah 0, seluruh kolom harus 0. Jika nilai pada baris sebelumnya adalah 1, Anda tahu bahwa semua baris di atasnya adalah 1 (dan selalu telah).
Dave Sherohman
0

buat matriks hasil dan atur semua nilai ke 1. pergi melalui matriks data segera setelah 0 ditemui, atur kolom baris matriks hasil ke 0

Pada akhir pass pertama, matriks hasil akan memiliki jawaban yang benar.

Terlihat sangat sederhana. Apakah ada trik yang saya lewatkan? Apakah Anda tidak diizinkan menggunakan set hasil?

EDIT:

Tampak seperti fungsi F #, tetapi itu sedikit curang karena meskipun Anda melakukan satu lintasan, fungsi tersebut dapat bersifat rekursif.

Sepertinya pewawancara sedang mencoba mencari tahu apakah Anda tahu pemrograman fungsional.

mson
sumber
1
Menggunakan set hasil akan mengambil memori ekstra.
cdeszaq
Pemrograman fungsional tidak akan mengubah array asli di tempatnya.
Svante
0

Yah, saya datang dengan solusi single-pass, in-place (non-rekursif) menggunakan 4 bools dan 2 loop counter. Saya belum berhasil menguranginya menjadi 2 bools dan 2 int, tapi saya tidak akan terkejut jika itu mungkin. Itu sekitar 3 membaca dan 3 menulis dari setiap sel, dan itu harus O (N ^ 2) yaitu. linear dalam ukuran array.

Butuh waktu beberapa jam untuk memecahkan teka-teki ini - saya tidak mau harus membuatnya di bawah tekanan wawancara! Jika saya membuat booboo saya terlalu lelah untuk menemukannya ...

Um ... Saya memilih untuk mendefinisikan "single-pass" sebagai membuat satu sapuan melalui matriks, daripada menyentuh setiap nilai sekali! :-)

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

sumber
0

saya harap Anda menikmati solusi 1-pass c # saya

Anda dapat mengambil elemen dengan O (1) dan hanya membutuhkan ruang satu baris dan satu kolom dari matriks

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
*/
Nick
sumber
Saya pikir satu-satunya masalah adalah Anda menggunakan dua array data tambahan untuk membuat ini berfungsi. Salah satu ketentuannya adalah tidak menggunakan memori ekstra. Tapi bagus! ini pada dasarnya adalah apa yang saya lakukan dalam jawaban saya :)
Kenny Cason
0

1 lulus, 2 boolean. Saya hanya harus mengasumsikan indeks integer di iterasi tidak masuk hitungan.

Ini bukan solusi lengkap tapi saya tidak bisa melewati titik ini.

Jika saya hanya bisa menentukan apakah 0 adalah asli 0 atau 1 yang dikonversi menjadi 0 maka saya tidak perlu menggunakan -1 dan ini akan berhasil.

Output saya seperti ini:

-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

Orisinalitas pendekatan saya menggunakan paruh pertama pemeriksaan baris atau kolom untuk menentukan apakah mengandung 0 dan setengah terakhir untuk menetapkan nilai - ini dilakukan dengan melihat x dan lebar-x dan kemudian y dan tinggi -Y di setiap iterasi. Berdasarkan hasil paruh pertama iterasi, jika 0 di baris atau kolom ditemukan, saya menggunakan paruh terakhir iterasi untuk mengubah 1 ke -1.

Saya baru menyadari ini bisa dilakukan dengan hanya 1 boolean menyisakan 1 untuk ...?

Saya memposting ini berharap seseorang mungkin berkata, "Ah, lakukan saja ini ..." (Dan saya menghabiskan terlalu banyak waktu untuk tidak memposting.)

Berikut kode di 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
rvarcher
sumber
0

Tidak ada yang menggunakan bentuk biner? karena hanya 1 dan 0. Kita bisa menggunakan vektor biner.

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

Inilah tesnya:

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)

Dan hasilnya:

Before...
10110
01110
11111
10111
11111
After...
00000
00000
00110
00000
00110
KFL
sumber
0

Anda dapat melakukan sesuatu seperti ini untuk menggunakan satu pass tetapi input dan output matrix:

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

di mana col(xy)bit dalam kolom berisi titik xy; row(xy)adalah bit di baris yang mengandung titik xy.nadalah ukuran dari matriks.

Kemudian cukup lewati input. Mungkin dapat diperluas agar lebih hemat ruang?

Warbum
sumber
0

Satu pemindaian matriks, dua boolean, tanpa rekursi.

Bagaimana cara menghindari lulus kedua? Pass kedua diperlukan untuk menghapus baris atau kolom ketika nol muncul di akhir mereka.

Namun masalah ini dapat diselesaikan, karena ketika kita memindai baris # i kita sudah tahu status baris untuk baris # i-1. Jadi, ketika kita memindai baris # i, kita dapat menghapus baris # i-1 secara bersamaan jika diperlukan.

Solusi yang sama berfungsi untuk kolom, tetapi kita perlu memindai baris dan kolom secara bersamaan sementara data tidak diubah oleh iterasi berikutnya.

Diperlukan dua boolean untuk menyimpan status baris pertama dan kolom pertama, karena nilainya akan berubah selama eksekusi bagian utama dari algoritma.

Untuk menghindari menambahkan lebih banyak boolean, kami menyimpan flag "clear" untuk baris dan kolom di baris dan kolom pertama dari matriks.

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();
}
Artemix
sumber
0

Sepertinya karya-karya berikut tanpa persyaratan ruang tambahan:

pertama-tama perhatikan bahwa mengalikan elemen-elemen dari baris kali dengan elemen-elemen dari baris di mana sebuah elemen, memberikan nilai yang diinginkan.

Agar tidak menggunakan ruang tambahan apa pun (tidak membuat matriks baru dan mengisinya, tetapi langsung menerapkan perubahan pada matriks), mulailah dari kiri atas matriks dan lakukan perhitungan untuk matriks ixi apa pun (yang "dimulai" pada (0) , 0)) sebelum mempertimbangkan elemen apa pun dengan indeks apa pun> i.

Semoga ini berhasil (havent testet)

DFF
sumber
Tampaknya salah. Asumsikan baris 0 hanya memiliki 1 nilai. Jika nilai akhir yang Anda tetapkan untuk (0,0) adalah 0, maka Anda kemudian akan mengatur baris lengkap ke 0, yang belum tentu benar. Anda sebenarnya perlu menyimpan 2 nilai per sel untuk melakukannya dengan gaya pemrograman dinamis, menggunakan prinsip Anda.
Eyal Schneider
tentu kamu benar Alih-alih menyimpan dua nilai, saya juga bisa menggunakan kemungkinan ketiga, katakan -1, yang berarti sel-sel yang 1 dalam matriks "lama" yang akhirnya akan digantikan oleh 0. Tentu saja, dengan cara itu, kita harus mengambil absolut nilai setelah perkalian. Pada akhirnya, semua -1 digantikan oleh 0.
DFF
0

Ini DIUJI untuk N berbeda dalam C ++, dan adalah:
SATU LULUS , DUA BULU , TANPA PEREKAMAN , TANPA MEMORI EKSTRA , TERLENGKAPNYA UNTUK BESARNYA SECARA ARBITRAR
(Sejauh ini tidak ada solusi di sini yang melakukan SEMUA ini.)

Lebih khusus, saya lucu dua loop counter tidak apa-apa. Saya memiliki dua const unsigned, yang hanya ada daripada dihitung setiap kali untuk dibaca. Interval loop luar adalah [0, N], dan interval loop dalam adalah [1, n - 1]. Pernyataan switch dalam loop sebagian besar ada untuk menunjukkan dengan sangat jelas bahwa itu hanya satu pass.

Strategi Algoritma:

Trik pertama adalah bagi kita satu baris dan kolom dari matriks itu sendiri untuk mengakumulasi konten matriks, memori ini menjadi tersedia dengan melepas semua yang benar-benar perlu kita ketahui dari baris pertama dan kolom menjadi dua boolean. Trik kedua adalah untuk mendapatkan dua pass dari satu, dengan menggunakan simetri dari sub-matriks dan indeksnya.

Sinopsis Algoritma:

  • Pindai baris pertama dan simpan jika semuanya berada dalam boolean, lakukan hal yang sama untuk kolom pertama yang menyimpan hasilnya dalam boolean kedua.
  • Untuk sub-matriks tidak termasuk baris pertama dan kolom pertama: iterate through, kiri ke kanan, atas ke bawah, karena orang akan membaca paragraf. Setelah mengunjungi setiap elemen, kunjungi juga elemen terkait yang akan dikunjungi jika mengunjungi sub-matriks secara terbalik. Untuk setiap elemen dikunjungi DAN nilainya ke tempat barisnya melintasi kolom pertama, dan juga DAN nilainya ke tempat kolomnya melintasi baris pertama.
  • Setelah pusat sub-matriks tercapai, terus mengunjungi dua elemen secara bersamaan seperti di atas. Namun sekarang setel nilai elemen yang dikunjungi ke DAN di tempat barisnya melintasi kolom pertama, dan di mana kolomnya melintasi baris pertama. Setelah ini, sub-matriks selesai.
  • Gunakan dua variabel boolean yang dihitung pada permintaan untuk mengatur baris pertama, dan kolom pertama ke nilai yang benar.

Implementasi Templatized C ++:

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;
}
Apriori
sumber
0

Ok, saya menyadari bahwa itu tidak cocok, tapi saya mendapatkannya dalam satu pass menggunakan bool dan byte alih-alih dua bools ... tutup. Saya juga tidak akan menjamin efisiensi, tetapi jenis pertanyaan ini sering membutuhkan solusi yang kurang optimal.

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; }
        }
    }
}
Walery Strauch
sumber
0

Anda dapat mengurutkannya dalam satu pass - jika Anda tidak menghitung mengakses matriks dalam urutan akses acak, yang menghilangkan manfaat melakukannya dengan single-pass di tempat pertama (cache-coherence / memory-bandwidth).

[edit: solusi sederhana, tetapi salah dihapus]

Anda harus mendapatkan kinerja yang lebih baik daripada metode single-pass dengan melakukannya dalam dua lintasan: satu untuk mengumpulkan informasi baris / kolom, dan satu untuk menerapkannya. Array (dalam urutan baris-utama) diakses secara koheren; untuk array yang melebihi ukuran cache (tetapi baris yang dapat ditampung dalam cache), data harus dibaca dari memori dua kali, dan disimpan satu kali:

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;
        }
    }
}
datang badai
sumber
0

Solusi paling sederhana yang dapat saya pikirkan adalah ditempelkan di bawah ini. Logikanya adalah untuk merekam baris dan kolom mana yang akan disetel nol saat iterasi.

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);
    }
}
geekprogrammer
sumber
0

Berikut ini adalah implementasi Ruby saya dengan tes yang disertakan, Ini akan mengambil ruang O (MN). Jika kita menginginkan pembaruan waktu nyata (ingin menunjukkan hasil ketika kita menemukan nol daripada menunggu loop pertama untuk menemukan nol) kita bisa membuat variabel kelas lain seperti @outputdan setiap kali kita menemukan nol kita memperbarui @outputdan tidak @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
Eki Eqbal
sumber
0

Kode di bawah ini membuat matriks ukuran m, n. Pertama-tama tentukan dimensi matriks. Saya ingin mengisi matriks [m] [n] dengan secara acak dengan angka antara 0..10. Kemudian buat matriks lain dari dimensi yang sama dan isi dengan -1s (final matrix). Kemudian beralih melalui matriks awal untuk melihat apakah Anda akan menekan 0. Ketika Anda menekan pada lokasi (x, y), pergi ke matriks akhir dan isi baris x dengan 0s dan kolom y dengan 0s. Pada akhir membaca matriks akhir, jika nilainya -1 (nilai asli) salin nilai di lokasi yang sama dari matriks awal ke 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;
}
pengguna3743369
sumber
Anda tidak memberikan penjelasan atau konteks apa pun pada kode yang telah Anda kirim.
Aaron
Semoga itu lebih baik sekarang. Terima kasih atas peringatannya. Saya ingin menjelaskan lebih banyak, jika tidak jelas untuk Anda.
user3743369
0

ini solusinya. Seperti yang dapat Anda lihat dari kode, diberikan matriks M * N, ia menetapkan seluruh baris menjadi nol setelah memeriksa nol di baris itu. Kompleksitas waktu dari solusi saya adalah O (M * N). Saya berbagi seluruh kelas yang memiliki larik statis yang dihuni untuk pengujian dan metode larik tampilan untuk melihat hasilnya di konsol.

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

}

}

Türkmen Mustafa Demirci
sumber