Установите каждую ячейку в матрице равной 0, если эта строка или столбец содержит 0

Учитывая матрицу NxN с 0s и 1s. Установите каждую строку, содержащую 0 для всех 0, и установите каждый столбец, содержащий 0 для всех 0 s.

Например

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

приводит к

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

Инженер Microsoft сказал мне, что есть решение, которое не требует дополнительной памяти, всего две логические переменные и один проход, поэтому я ищу этот ответ.

Кстати, представьте, что это бит-матрица, поэтому только 1 и 0 могут находиться в матрице.

Ответ 1

Хорошо, поэтому я устал, как и здесь 3AM, но у меня есть первая попытка на месте с точностью до 2 проходов на каждое число в матрице, поэтому в O (NxN) и линейна по размеру матрицы.

Я использую 1-й столбец и первую строку в качестве маркеров, чтобы знать, где находятся строки/столбцы с только 1. Тогда есть 2 переменные l и c, чтобы помнить, что все 1-я строка/столбец тоже 1. Таким образом, первый проход устанавливает маркеры и сбрасывает остальное на 0.

Второй проход устанавливает 1 в местах, где строки и столбцы, помеченные как 1, и сбрасывают 1-ю строку /col в зависимости от l и c.

Я сильно сомневаюсь, что я могу сделать за один проход, поскольку квадраты в начале зависят от квадратов в конце. Возможно, мой второй проход можно сделать более эффективным...

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)

Ответ 2

Это невозможно сделать за один проход, поскольку один бит влияет на биты до и после него в любом порядке. IOW Независимо от того, в каком порядке вы проходите массив, вы можете позже перейти к 0, что означает, что вам нужно вернуться назад и изменить предыдущий 1 на 0.

Update

Люди, похоже, думают, что, ограничив N некоторым фиксированным значением (например, 8), вы можете решить, что это один проход. Хорошо, что a) отсутствует точка и b) не оригинальный вопрос. Я бы не поставил вопрос о сортировке и ожидал ответа, который начинался "предполагая, что вы хотите сортировать только 8 вещей...".

Тем не менее, это разумный подход, если вы знаете, что N фактически ограничено 8. Мой ответ выше отвечает на исходный вопрос, который не имеет такого поиска.

Ответ 3

Итак, моя идея - использовать значения в последней строке/столбце в качестве флага, чтобы указать, все ли значения в соответствующем столбце/строке равны 1 с.

Используя Zig Zag scan по всей матрице ЗА ИСКЛЮЧЕНИЕМ последней строки/столбца. В каждом элементе вы устанавливаете значение в последней строке/столбце в соответствии с логическим И сами по себе со значением в текущем элементе. Другими словами, если вы нажмете 0, окончательная строка/столбец будет установлена ​​в 0. Если вы это 1, значение в последней строке/столбце будет равно 1, только если оно уже равно 1. В любом случае установите текущий элемент на 0.

Когда вы закончите, ваша заключительная строка/столбец должна иметь 1 с, если соответствующий столбец/строка заполняется 1 сек.

Проведите линейное сканирование по последней строке и столбцу и ищите 1 с. Установите 1s в соответствующих элементах в теле матрицы, где окончательная строка и столбец равны 1 с.

Кодирование будет непростым, чтобы избежать ошибок при запуске и т.д., но он должен работать за один проход.

Ответ 4

У меня есть решение здесь, оно выполняется за один проход и делает всю обработку "на месте" без дополнительной памяти (за исключением роста стека).

Он использует рекурсию для задержки записи нулей, которая, естественно, уничтожит матрицу для других строк и столбцов:

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

Ответ 5

Я не думаю, что это выполнимо. Когда вы находитесь на первом квадрате, и его значение равно 1, вы не можете узнать, что значения других квадратов в одной и той же строке и столбце. Поэтому вы должны проверить их, и если есть нуль, вернитесь к первому квадрату и измените его значение на ноль. Я рекомендую сделать это за два прохода - первый проход собирает информацию о том, какие строки и столбцы должны быть обнулены (информация хранится в массиве, поэтому мы используем дополнительную память). Второй проход изменяет значения. Я знаю, что не решение, которое вы ищете, но я считаю это практичным. Ограничения, предоставленные вами, делают проблему неразрешимой.

Ответ 6

Я могу сделать это с двумя целыми переменными и двумя проходами (до 32 строк и столбцов...)

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

Ответ 7

проблема может быть решена за один проход

сохранение матрицы в массиве я 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 .

теперь напечатать все значения как 0 для значений я и j, сохраненных в и b остальные значения равны 1, т.е. (3,3) (3,4) (5,3) и (5,4)

Ответ 8

Хороший вызов. Этот вид решения использует только два булевых файла, созданных в стеке, но логические элементы создаются несколько раз в стеке, поскольку функция рекурсивна.

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

Это сканирование в шаблоне, например:

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

и т.д.

И затем изменение значений в этом шаблоне при возврате каждой из функций сканирования. (Снизу вверх):

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

и т.д.

Ответ 9

Другое решение, которое принимает два прохода, состоит в том, чтобы накапливать ANDs по горизонтали и по вертикали:

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    

Я думал, что смогу создать такой алгоритм, используя бит четности, Коды Хэмминга или динамическое программирование, возможно, используя эти два логических значения как 2-битное число, но я не имел успеха пока.

Не могли бы вы перепроверить выражение о проблеме с вашим инженером и сообщить нам? Если действительно есть решение, я хочу продолжать устранять проблему.

Ответ 10

Сохраните одну переменную, чтобы отслеживать, что все строки ANDed вместе.

Если строка равна -1 (все 1s), сделайте следующую строку ссылкой на эту переменную

Если строка ничего, но она равна 0. Вы можете сделать все за один проход. Псевдопользователей-код:

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

Это должно сделать это за один проход - но здесь есть предположение, что N достаточно мал, чтобы процессор выполнял арифметику в одной строке, иначе вам нужно будет перебирать каждую строку, чтобы определить если все это 1 или нет, я верю. Но, учитывая, что вы спрашиваете о algos и не ограничиваете мое оборудование, я бы просто начал свой ответ с "Построить процессор, поддерживающий N-разрядную арифметику..."

Вот пример того, как это можно сделать в C. Примечание. Я утверждаю, что значения и arr вместе взятые представляют собой массив, а p и numproduct - это мой итератор, а переменные AND и переменные используются для реализации проблемы. (Я мог бы зациклиться на arr с помощью арифметики указателя для проверки моей работы, но один раз было достаточно!)

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

Это дает 0, 0, 6, 0, 6, что является результатом для данных входов.

Или в PHP, если люди думают, что мои игры в стеках на C обманывают (я предлагаю вам, чтобы это не так, потому что я должен был хранить матрицу в любом случае, как мне нравится):

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

Я что-то пропустил?

Ответ 11

Хорошо, это решение, которое

  • использует только одно дополнительное значение для рабочего хранилища.
  • не использует рекурсию.
  • один проход только N, даже N * N.
  • будет работать для других значений N, но потребуются новые #defines.
#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;
    }

Ответ 12

На самом деле. Если вы просто хотите запустить алгоритм и распечатать результаты (т.е. Не восстановить их, то это можно легко сделать за один проход. Проблема возникает, когда вы пытаетесь изменить массив при запуске алгоритма.

Вот мое решение. Оно просто включает ANDing значения строк/столбцов для элемента givein (i, j) и его распечатку.

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

Ответ 13

Я попытался решить эту проблему на С#.

Я использовал две переменные цикла (i и j), кроме фактической матрицы, и n, представляющую ее размерность

Логика, которую я пробовал, - это:

  • Вычислить AND для строк и столбцов, участвующих в каждом концентрическом квадрате матрицы.
  • Сохраните его в своих угловых ячейках (я сохранил их в порядке против часовой стрелки)
  • Две переменные bool используются для сохранения значений двух углов при оценке конкретного квадрата.
  • Этот процесс завершится, когда внешний цикл (i) будет в середине.
  • Оценить результаты других ячеек на основе угловых ячеек (для остальной части i). Пропустите угловые ячейки во время этого процесса.
  • Когда я достигает n, все ячейки будут иметь свой результат, за исключением угловых ячеек.
  • Обновить угловые ячейки. Это дополнительная итерация до длины n/2, отличной от ограничения одиночного прохода, упомянутого в проблеме.

код:

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

Ответ 14

Несмотря на невозможность получения ограничений, наиболее эффективным с точки зрения пространства способом является перемещение матрицы в перекрывающемся чередующемся ряду строк/столбцов, что делает шаблон похож на укладку кирпичей зигзагообразным способом:

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

Используя это, вы должны войти в каждую строку/столбец, как указано, и если вы столкнулись с 0 в любое время, установите логическую переменную и повторите эту строку/столбец, установив записи в 0, когда вы идете.

Это не требует дополнительной памяти и будет использовать только одну логическую переменную. К сожалению, если "крайний" край установлен равным 0, это наихудший случай, и вы дважды идете по всему массиву.

Ответ 15

создайте матрицу результатов и установите для всех значений значение 1. пройдите через матрицу данных, как только встретится 0, установите столбец строк матрицы результатов равным 0

В конце первого прохода матрица результатов будет иметь правильный ответ.

Выглядит довольно просто. Есть ли трюк, который мне не хватает? Вам не разрешено использовать результирующий набор?

EDIT:

Похож на функцию F #, но это немного изменяет, так как даже если вы выполняете один проход, функция может быть рекурсивной.

Похоже, интервьюер пытается выяснить, знаете ли вы функциональное программирование.

Ответ 16

Ну, я придумал однопроходное (нерекурсивное) решение с использованием 4 bools и 2 счетчиков циклов. Мне не удалось уменьшить его до 2 балов и 2 ints, но я не удивился бы, если бы это было возможно. Он составляет около 3-х чтения и 3 записи каждой ячейки, и он должен быть O (N ^ 2), т.е. линейный по размеру массива.

Мне потребовалось пару часов, чтобы разобраться с этим - я бы не захотел придумать это под давлением интервью! Если я сделал booboo, я слишком устал, чтобы заметить это...

Ум... Я решил определить "однопроходный", как один промах через матрицу, а не касаться каждого значения один раз!: -)

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

Ответ 17

Вы можете отсортировать его за один проход - если вы не учитываете доступ к матрице в порядке произвольного доступа, что исключает преимущества выполнения этого однопроходного в первую очередь (кеш-когерентность/пропускная способность памяти).

[править: простое, но неправильное решение удалено]

Вы должны получить лучшую производительность, чем любой однопроходный метод, выполнив это за два прохода: один для накопления информации о столбцах/столбцах и один для ее применения. Массив (в строчном порядке) доступен когерентно; для массивов, превышающих размер кеша (но строки которого могут входить в кеш), данные должны считываться из памяти дважды и сохраняться один раз:

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

Ответ 18

Надеюсь, вам понравится мое решение с одним проходом С#

вы можете получить элемент с помощью O (1) и только пространство одной строки и одного столбца матрицы

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
*/

Ответ 19

Хорошо, я понимаю, что это не совсем совпадение, но я получил его за один проход, используя bool и байт вместо двух bools... close. Я также не стал бы ручаться за его эффективность, но эти типы вопросов часто требуют менее оптимальных решений.

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

Ответ 20

1 проход, 2 булева. Я просто должен предположить, что целые индексы в итерациях не учитываются.

Это не полное решение, но я не могу пройти этот момент.

Если бы я мог только определить, является ли 0 исходным 0 или 1, который был преобразован в 0, тогда мне не пришлось бы использовать -1, и это сработало бы.

Мой вывод выглядит следующим образом:

-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

Оригинальность моего подхода заключается в использовании первой половины проверки строки или столбца, чтобы определить, содержит ли она 0 и последнюю половину для установки значений - это делается путем просмотра x и width-x, а затем y и height-y на каждой итерации. Основываясь на результатах первой половины итерации, если было найдено 0 в строке или столбце, я использую последнюю половину итерации, чтобы изменить 1 на -1.

Я просто понял, что это можно сделать только с 1 булевым выходом 1...?

Я отправляю это в надежде, что кто-то скажет: "Ах, просто сделайте это..." (И я потратил слишком много времени, чтобы не публиковать сообщения.)

Здесь код в 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 at x and width - x positions. Halfway through I'll konw if there 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

Ответ 21

Вы можете сделать что-то подобное, чтобы использовать один проход, но матрицу ввода и вывода:

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

где col(xy) - бит в столбце, содержащем точку xy; row(xy) - это бит в строке, содержащей точку xy. n - размер матрицы.

Затем просто зациклируйте вход. Возможно ли расширяемое пространство для большей экономии пространства?

Ответ 22

Никто не использует двоичные формы? так как это только 1 и 0. Мы можем использовать двоичные векторы.

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

Здесь тест:

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)

И вывод:

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

Ответ 23

Одно сканирование матрицы, два булева, без рекурсии.

Как избежать второго прохода? Второй проход необходим для очистки строк или столбцов, когда нуль появляется в конце.

Однако эта проблема может быть решена, потому что при сканировании строки #i мы уже знаем статус строки для строки # i-1. Итак, пока мы сканируем строку #i, мы можем одновременно очистить строку # i-1, если это необходимо.

То же самое решение работает для столбцов, но нам нужно сканировать строки и столбцы одновременно, пока данные не будут изменены следующей итерацией.

Для хранения статуса первой строки и первого столбца требуется два булевых элемента, поскольку их значения будут изменены во время выполнения основной части алгоритма.

Чтобы избежать добавления дополнительных логических элементов, мы сохраняем флаг "clear" для строк и столбцов в первой строке и столбце матрицы.

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

Ответ 24

выглядит следующим образом без дополнительных требований к пространству:

сначала обратите внимание, что умножение элементов строки на разность элементов строки, в которой находится элемент, дает желаемое значение.

Чтобы не использовать какое-либо дополнительное пространство (не создавая новую матрицу и не заполняя ее, а вместо этого применяйте изменения непосредственно к матрице), начинайте левую верхнюю часть матрицы и выполняйте вычисления для любой матрицы ixi (которая "запускает" ) в (0,0)), прежде чем рассматривать любой элемент с любым индексом > i.

надеюсь, что это сработает (havent testet)

Ответ 25

Это TESTED для разных N в С++ и:
ОДИН ПАРОЛЬ, ДВА КОРОБКИ, НЕТ РЕКРЕССИИ, НЕТ ДОПОЛНИТЕЛЬНОЙ ПАМЯТИ, ОТВЕРСТИЙ ДЛЯ ARBITRARLY LARGE N
(Пока что ни одно из решений здесь не ВСЕ).

В частности, я занимаюсь двумя счетчиками в цикле, все в порядке. У меня есть два const unsignments, которые существуют, а не только вычисляются каждый раз для удобства чтения. Интервал внешнего цикла равен [0, N], а интервал внутреннего цикла - [1, n - 1]. Оператор switch находится в цикле, в основном, существует, чтобы четко показать, что это действительно один проход.

Стратегия алгоритма:

Первый трюк - это нам строка и столбец из самой матрицы, чтобы накапливать содержимое матрицы, эта память становится доступной, выгружая все, что нам действительно нужно знать из первой строки и столбца, в два булева. Второй трюк состоит в том, чтобы получить два прохода из одного, используя симметрию подматрицы и ее индексы.

Алгоритм Сводка:

  • Отсканируйте первую строку и сохраните, если все они являются логическими, выполните то же самое для первого столбца, в котором будет сохраняться результат во втором булевом языке.
  • Для подматрицы, исключающей первую строку и первый столбец: итерацию через, слева направо, сверху вниз, так как можно было бы прочитать абзац. При посещении каждого элемента также посетите соответствующий элемент, который будет посещен, если вы перейдете в подматрицу в обратном порядке. Для каждого посетившего элемент И его значение в том, где его строка пересекает первый столбец, а также И его значение, где его столбец пересекает первую строку.
  • Как только центр подматрицы достигнут, продолжайте посещать два элемента одновременно, как указано выше. Однако теперь установите значение посещенных элементов в И, где его строка пересекает первый столбец и где его столбец пересекает первую строку. После этого субматрица завершена.
  • Используйте две логические переменные, вычисленные при попрошайничестве, чтобы установить первую строку, а первый столбец - их правильные значения.

Планируемая реализация на С++:

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

Ответ 26

Вот моя реализация Ruby с включенным тестом. Это займет пространство O (MN). Если мы хотим обновить в реальном времени (например, чтобы показать результаты, когда мы находим нули, а не ожидаем первый цикл поиска нулей), мы можем просто создать другую переменную класса, такую ​​как @output, и всякий раз, когда мы находим нуль, мы обновляем @output и не @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

Ответ 27

Простейшее решение, о котором я могу думать, приведено ниже. Логика заключается в том, чтобы записать, какая строка и столбец устанавливают нуль во время итерации.

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

Ответ 28

В приведенном ниже коде создается матрица размера m, n. Сначала определите размеры матрицы. Я хотел случайно заполнить матрицу [m] [n] с номерами от 0..10. Затем создайте другую матрицу с одинаковыми размерами и заполните ее -1 с (конечная матрица). Затем проведите по исходной матрице, чтобы увидеть, ударишь ли ты 0. Когда вы нажмете на место (x, y), перейдите к финальной матрице и заполните строку x 0 и столбцом y 0. В конце прочитайте финальную матрицу, если значение равно -1 (исходное значение), скопируйте значение в том же месте исходной матрицы в 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;
}

Ответ 29

вот мое решение. Как вы можете видеть из кода, учитывая матрицу M * N, она устанавливает всю строку в ноль, как только она проверяет нуль в этой строке. Сложность времени моего решения равна O (M * N). Я разделяю весь класс, который имеет статический заполненный массив для тестирования и метод отображения, чтобы увидеть результат в консоли.

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

}

}