해당 행이나 열에 0이 포함되어 있으면 행렬의 모든 셀을 0으로 설정하십시오.


152

0과 1의 NxN 행렬이 주어집니다. 을 포함하는 모든 행 세트 0모두 0들와를 포함하는 모든 열 설정 0모두 0들.

예를 들어

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 엔지니어는 여분의 메모리가 필요없고 부울 변수 두 개와 패스 한 개만 포함 된 솔루션이 있다고 대답했습니다.

BTW, 비트 행렬이라고 가정하면 1과 0만이 행렬에있을 수 있습니다.


1
응? "언제든지"무엇입니까? 매트릭스에서 어떤 순서로 요소를 만나고 있습니까? 그리고 모든 비트를 만나면 어쨌든 모든 0을 얻지 못합니까?
ShreevatsaR

글쎄, 요소를 만나기로 결정한 순서는 결정이며, 적절한 요소를 0으로 설정해야한다는 것입니다. 모든 비트가 0으로 설정되어 있으면 매트릭스는 여전히 0으로 채워집니다.
jaircazarin-old-account

"적절한 요소"는 무엇입니까? 두 개의 매트릭스, 하나는 "소스"매트릭스와 하나는 "타겟"매트릭스 를 제공 받았으며 "타겟"매트릭스를 얻기 위해 요소를 "인 카운트"하는 순서를 결정해야합니까?
ShreevatsaR

1
나는 당신이 '1 패스'생각을 위해 무언가를 mi다고 생각합니다. 그것은, 추가 메모리없이,하지만 2 개 패스 선형 단 2 부울 ;-) 그래서 강력하게 그가 의미의 해결책이 가정을 수행 할 수 있습니다 (아래 참조)
표트르 Lesnicki

1
문제 설명이 실제로 올바른지 친구와 다시 확인 하시겠습니까? 나는 해밍 코드 또는 패리티 비트로이 작업을 수행 할 수 있다고 생각했지만 지금까지는 성공하지 못했지만 문제는 계속 내 머리에 고정됩니다. :)
csl

답변:


96

자, 여기 3AM이기 때문에 피곤하지만 행렬의 각 숫자에 정확히 2 패스를 사용하여 첫 번째 시도를 시도하므로 O (NxN)에서 행렬의 크기는 선형입니다.

첫 번째 열과 첫 번째 행을 마커로 사용하여 행이 1 / 1 인 행을 알 수 있습니다. 그런 다음 첫 번째 행 / 열도 모두 1인지 기억해야 할 두 개의 변수 l과 c가 있습니다. 따라서 첫 번째 패스는 마커를 설정하고 나머지는 0으로 재설정합니다.

두 번째 패스는 행과 열이 1로 표시된 곳에 1을 설정하고 l과 c에 따라 첫 번째 라인 / 콜을 재설정합니다.

처음에 사각형이 끝에있는 사각형에 따라 1 패스로 할 수 있다고 강하게 의심합니다. 어쩌면 내 두 번째 패스를보다 효율적으로 만들 수 있습니다 ...

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)

여기서 한 가지 문제는 n> sizeof (c)이면 고장입니다. 일반적인 경우 n에서 작동하도록 이것을 확장하려면 비트 필드의 크기를 동적으로 조정해야합니다. 이는 문제에 의해 주어진 제약 조건을 위반한다고 생각합니다.
Adam

아니오, c는 비트 필드가 아니며 단지 부울입니다. & =는 비트 단위 연산이 아닙니다 (물론 1 비트 값입니다). c는 첫 번째 열이 모두 1 (true)인지 0 (false)인지를 알려주기 때문에 존재합니다.
Steve Jessop

2
맨 위 행이 [0,1,1,1 ...]이면 실패합니다. 버그 수정은 l 대신 1을 m [0] [0]으로 초기화하는 것입니다.
paperhorse

범위 (1, N)의 i에 대해 실제로 l = 1 : l & = m [0] [i]는 범위 (N)의 i에 대해 l = 1이어야합니다. l & = m [0] [i]
Kristof Neirynck

1
BTW, 나는 두 번째 패스의 조건이 다음과 같아야한다고 생각합니다. if m [i] [0] | m [0] [j] :
jaircazarin-old-account

16

단일 비트는 어떤 순서로든 비트 전후에 비트에 영향을주기 때문에 한 번에 수행 할 수 없습니다. IOW 배열을 순회하는 순서에 관계없이 나중에 0에 도달 할 수 있습니다. 다시 돌아가서 이전 1을 0으로 변경해야합니다.

최신 정보

사람들은 N을 고정 값 (예 : 8)으로 제한하면이 문제를 해결할 수 있다고 생각하는 것 같습니다. 그것은 a) 요점을 놓치고 b) 원래의 질문이 아닙니다. 나는 정렬에 대한 질문을 게시하지 않고 "8 가지만을 정렬하고 싶다고 가정"하는 대답을 기대합니다.

즉, N이 실제로 8로 제한되어 있다는 것을 알고 있다면 합리적인 접근 방법입니다. 위의 대답은 그러한 회귀가없는 원래의 질문에 대답합니다.


추가 메모리없이 한 번에 수행 할 수 없습니다. 결과를 저장할 다른 NxN 행렬이 있으면 한 번에 수행 할 수 있습니다. 마찬가지로 일부 비트 트위들과 두 번의 통과로 추가 메모리없이 수행 할 수 있습니다.
paxos1977

2
임시 행렬을 사용하더라도 한 번에 한 번에 처리 할 수 ​​없거나 그렇지 않은 이상한 것이 있습니다. 행 / 열 정보를 추론하려면 하나의 패스가 필요하고 모든 것을 설정하려면 하나의 패스가 필요합니다.
Lasse V. Karlsen 08.

행당 하나의 고유 한 0이 아닌 값만 가능하다는 것을 인식하고 참조로 지정 하여이 문제를 해결했습니다.
Daniel Papasian

@ ceretullis, lassevk : 여전히 한 번에 할 수 없다고 생각합니다. 두 번째 행렬을 통과하면 계산해야합니다. 그렇지 않으면 한 번에 행렬을 복사하고 원하는 사본으로 작업 할 수 있습니다. @Daniel Papasian : 귀하의 솔루션은 확장되지 않는 경우 INT / 긴 / 어떤에서 N> #bits
Draemon

Draemon, 기술은 확장 성이 뛰어나고 수학에 불과합니다. 하드웨어를 구축하거나 소프트웨어 기술을 사용하여 단어 크기보다 큰 숫자를 조작 할 수 있습니다. IMHO
Daniel Papasian 2009

10

그래서 내 생각은 마지막 행 / 열의 값을 플래그로 사용하여 해당 열 / 행의 모든 ​​값이 1인지 여부를 나타냅니다.

마지막 행 / 열을 제외한 전체 행렬을 통해 지그재그 스캔 을 사용합니다 . 각 요소에서 최종 행 / 열의 값을 현재 요소의 값과 함께 논리 AND로 설정합니다. 다시 말해, 0을 누르면 최종 행 / 열이 0으로 설정됩니다. 1이면 최종 행 / 열의 값은 이미 1 인 경우에만 1이됩니다. 어쨌든 현재 요소를 0으로 설정하십시오.

완료되면 해당 열 / 행이 1로 채워진 경우 최종 행 / 열에 1이 있어야합니다.

마지막 행과 열을 통해 선형 스캔을 수행하고 1을 찾으십시오. 마지막 행과 열이 모두 1 인 행렬의 본문에서 해당 요소에 1을 설정합니다.

코딩은 개별 오류를 피하는 것이 까다로울 수 있지만 한 번에 작동해야합니다.


아주 좋은 ... 나는 같은 줄에서 생각하고 있었지만 그 정보를 저장하기 위해 마지막 행 / 열을 사용하지 못했습니다. 그래서 Nx1 배열 쌍에 대한 추가 메모리가 붙어있었습니다.
Dave Sherohman

1
그것은 나에게 2 개의 패스처럼 보인다 – 1 개의 패스는 지그재그 스캔이고, 2 개의 패스는 "마지막 행과 열이 모두 1 인 매트릭스의 해당 요소에서 1을 설정한다"이다.
Adam Rosenfield 2016

지그재그 스캔 (누군가가 지적한대로 엄격하게 필요하지는 않음)은 모든 행을 통과하지만 마지막 행 / 열입니다. 따라서 마지막 / 행 열을 스캔해도 이전에 스캔 한 요소는 복제되지 않습니다. 따라서 하나의 패스. 즉, N * N 행렬의 경우 O (N ^ 2)입니다.
Alastair

6

여기에 해결책이 있으며 단일 패스로 실행되며 추가 메모리없이 "제자리에서"모든 처리를 수행합니다 (스택을 늘리기 위해 저장).

그것은 재귀를 사용하여 물론 다른 행과 열에 대한 행렬을 파괴하는 0의 쓰기를 지연시킵니다.

#include <iostream>

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

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

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

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

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

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

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

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

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

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

    return zero;
}

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

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

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

2
좋은 해결책이지만 기술적으로는 허용되는 두 부울보다 많은 메모리를 사용하고 있습니다 (스택에 있지만).
csl

1
이것은> 1 패스입니다. checkRow 및 checkCol에서 액세스 할 때 (rowIndex, i) 및 (i, colIndex)를 인쇄하면 각 요소가 여러 번 액세스되는 것을 볼 수 있습니다.
Draemon

Draemon : 맞습니다. 수수께끼 제작자로부터 "싱글 패스"에 대한 명확한 정의가 필요하다고 생각합니다. 그가 실제로 각 요소에 한 번만 액세스 할 수 있음을 의미한다면 다른 솔루션이 필요합니다.
Adam

원래 문제 (전화 게임을 통해 우리에게 왔음)는 문제가 "제자리에서"해결되어야한다는 것을 의미한다고 생각합니다. 즉, 매트릭스의 다른 사본이 없습니다. 더 최적의 솔루션은 처리를위한 스토리지와 같은 임시 스왑 ()도 필요하지 않습니다.
Adam

또한 제약 조건이 결과 기계 코드를 참조하고 있는지 의심 스럽습니다. 즉, 내가 제공 한 "코드"는 2 개의 부울 만 사용합니다. 내 컴파일러가 수행하는 최적화에 따라 전체적인 내용이 인라인되거나 다른 것을 아는 사람이있을 수 있습니다. 내 솔루션이 맞다고 생각합니다.)
Adam

4

나는 그것이 가능하다고 생각하지 않습니다. 첫 번째 사각형에 있고 그 값이 1이면 같은 행과 열에있는 다른 사각형의 값이 무엇인지 알 수있는 방법이 없습니다. 따라서 그것들을 확인하고 0이 있으면 첫 번째 사각형으로 돌아가서 그 값을 0으로 변경하십시오. 두 단계로 수행하는 것이 좋습니다. 첫 번째 단계에서는 어떤 행과 열을 제로화해야하는지에 대한 정보를 수집합니다 (정보는 배열에 저장되므로 추가 메모리를 사용하고 있음). 두 번째 패스는 값을 변경합니다. 나는 그것이 당신이 찾고있는 해결책이 아니라는 것을 알고 있지만 그것이 실용적인 것이라고 생각합니다. 주어진 제한 조건으로 인해 문제점을 해결할 수 없습니다.


추가 배열없이 거의 동일한 솔루션 (아래 참조)이 있습니다. 그리고 선형 시간 (단, 2 개 패스지라도) 인
표트르 Lesnicki

@Piotr : 네, 두 번째 패스는 피할 수없는 것 같습니다. 내가 제안한 행과 열 정보를 저장하는 배열을 도입하면 검사 및 값 변경이 적을수록 알고리즘이 더 간단하고 조금 빨라집니다. 스토리지와 효율성 간의 절충점입니다.
Boyan

3

두 개의 정수 변수와 두 개의 패스 (최대 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));

이 C #입니까? ~는 무엇을 의미합니까?
sker

C ++입니다. ~변수의 모든 비트를 반전시킵니다. 0x00000000은 0x00000000이됩니다. 기본적으로 모든 것으로 시작하고 0을 찾을 때 행 / 열의 비트를 지 웁니다. CompleteCols에는 비트 2와 3이 있고 CompleteRows에는 비트 2와 4가 있습니다 (0 기반).
Eclipse

그런 다음 매트릭스의 비트를 CompleteCols 및 CompleteRows의 비트에 모두 설정하면됩니다.
Eclipse

3

한 번에 문제를 해결할 수 있습니다

행렬을 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 .

이제 a 및 b에 저장된 i 및 j의 값에 대해 모든 값을 0으로 인쇄합니다. 나머지 값은 1입니다. 즉 (3,3) (3,4) (5,3) 및 (5,4)


1

두 단계를 거치는 또 다른 솔루션은 가로 및 세로로 AND를 누적하는 것입니다.

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 비트 숫자로 사용하여 이러한 알고리즘을 설계 할 수 있다고 생각 했지만 아직 성공하지 못했습니다.

엔지니어에게 문제 설명을 다시 확인하여 알려주시겠습니까? 실제로 해결책 있다면 문제에서 계속 치핑하고 싶습니다.


1

AND로 묶인 모든 행이 무엇인지 추적하려면 단일 변수를 유지하십시오.

행이 -1 (모두 1)이면 다음 행을 해당 변수에 대한 참조로 만듭니다.

행이 아무것도 아닌 경우 0입니다. 한 번에 모든 작업을 수행 할 수 있습니다. 슈도 코드 :

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

단일 패스에서 그렇게해야하지만 CPU가 단일 행에서 산술을 수행하기에 N이 작다는 가정이 있습니다. 그렇지 않으면 각 행을 반복하여 모든 행인지 확인해야합니다 1s 또는 믿습니다. 그러나 알고리즘에 대해 질문하고 하드웨어를 제한하지 않으면 "N 비트 산술을 지원하는 CPU 빌드 ..."로 대답을 시작합니다.

다음은 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);

뭔가 빠졌습니까?


N이 int / long / what의 비트 수보다 크면 작동하지 않으므로 계산하지 않습니다.
Draemon

또한 0이 배열의 맨 아래에 있으면 값을 포착하지 않습니다 (값 [] = {-1, -9, -1, 14, -10}으로 시도).
Eclipse

Draemon, 나는 대답에서 하드웨어 제약이 없으면 "N 비트 산술을 지원하는 CPU 구축"으로 시작한다고 대답했습니다.
Daniel Papasian

조쉬, 안 따라와 C 또는 PHP 솔루션과 제안한 배열을 사용하여 6 0 6 0 0을 얻습니다. 정답이라고 생각합니다.
Daniel Papasian 2009

@Daniel-N은 상수가 아니기 때문에 할 수 없습니다. 게다가 "1Mbit 단어로 새 컴퓨터를 만드는 것은 합리적인 알고리즘 단계가 아닙니다.
Draemon

1

좋은 challange. 이 솔루션은 스택에 생성 된 두 개의 부울 만 사용하지만 함수가 재귀 적이므로 스택에 부울이 여러 번 생성됩니다.

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

등등


스택에 두 개 이상의 부울을 계속 사용하기 때문에 이것이 올바르지 않은 것 같습니다.
csl

내가 슬픈 것처럼 두 종류의 부울. 이것이 그가 제공 한 사양에 가장 가깝습니다. 나는 실제 해결책을보고 싶습니다. 그것이 가능하다면.
eaanon01

요구 사항이 스택을 늘리는 것을 의미한다고 생각하지 않습니다. 나는 이것이 완벽하게 유효한 해결책이라고 생각합니다.
Adam

그것은 또한 나의 thougt입니다. 그러나 다른 사람이 더 나은 솔루션을 게시 할 때까지 확신 할 수 없습니다. 적어도 내 솔루션은 컴파일 가능하며 누구나 확인할 수 있습니다. :) ... 실제 문제에 대한 의사 코드를 찾지 못했습니다. Thnx
eaanon01

1

이 솔루션은

  • 스토리지 작업에 하나의 여분의 긴 값만 사용합니다.
  • 재귀를 사용하지 않습니다.
  • 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;
    }

확실히 좋은 해결책입니다. 그리고 여기에있는 모든 솔루션이 하나 이상의 요구 사항을 무시한다고 가정합니다. N의 최대 허용 값을 가진 솔루션을 가진 것은 세계에서 최악의 일이 하나 :)에 이렇게 좋은 일이 아니다 그래서
아담

N을 8로 제한하고이 요구 사항을 충족한다고 주장하는 것은 단순한 바보입니다. 이것은 일반적인 해결책이 아닙니다. 이 질문에 N의 크기에 대한 제한이 없었으므로 하위 문제 만 해결했습니다.
Draemon

그러나 이러한 모든 솔루션은 어떤 식 으로든 N에 제한이 있습니다.
AnthonyLambert

그것이 N의 한 패스라고 말하는 것은 분명히 완전히 잘못되었습니다. 원래 행렬에서 각 위치의 값을 읽는 것만으로도 O (N ^ 2)이며 솔루션을 계산할 수 있으려면 각 위치의 값을 한 번 이상 읽어야합니다. 값을 오랫동안 단일 비트로 저장하더라도 O (N ^ 2) 비트가 있으므로 각 비트에 액세스하는 것은 O (N ^ 2)가됩니다.
Alderath

RowGrid 값이 전체 그리드를 저장하는 것은 분명히 한 번의 통과이며, 첫 번째 읽은 후에 옵티마이 저가 좋은 경우 전체 알고리즘에 대한 프로세서 레지스터 중 하나가됩니다.
AnthonyLambert

1

사실은. 알고리즘을 실행하고 결과를 인쇄하려면 (즉, 복원하지 않으면) 한 번에 쉽게 수행 할 수 있습니다. 알고리즘을 실행할 때 배열을 수정하려고하면 문제가 발생합니다.

여기 내 솔루션이 있습니다. 단지 (i, j) 요소의 행 / 열 값을 AND로 AND 인쇄하는 것과 관련이 있습니다.

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

void process();

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


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

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

1

C # 에서이 문제를 해결하려고했습니다.

실제 행렬과 차원을 나타내는 n을 제외하고 두 개의 루프 변수 (i와 j)를 사용했습니다.

내가 시도한 논리는 다음과 같습니다.

  1. 행렬의 각 동심원에 관련된 행과 열에 대한 AND 계산
  2. 모서리 셀에 저장하십시오 (시계 반대 방향으로 저장했습니다)
  3. 두 개의 부울 변수는 특정 제곱을 평가할 때 두 모서리의 값을 유지하는 데 사용됩니다.
  4. 이 과정은 외부 루프 (i)가 중간에있을 때 종료됩니다.
  5. 코너 셀 (나머지 i의 ​​경우)을 기준으로 다른 셀의 결과를 평가합니다. 이 과정에서 코너 셀을 건너 뜁니다.
  6. i가 n에 도달하면 모서리 셀을 제외한 모든 셀의 결과가 나타납니다.
  7. 코너 셀을 업데이트하십시오. 이것은 문제에서 언급 한 단일 패스 제약 조건 이외의 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;
            }
        }
    }
}

1

One Pass-입력을 한 번만 통과했지만 새 배열과 두 개의 추가 부울 변수 만 사용했습니다.

public static void main(String[] args) {

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

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

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

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

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

            }

        }

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

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

    }

0

제약 조건을 감안할 때 불가능하지만 가장 효율적으로 수행하는 방법은 겹치는 행 / 열 방식으로 매트릭스를 통과하여 지그재그 방식으로 벽돌을 놓는 것과 유사한 패턴을 만드는 것입니다.

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

이것을 사용하면 표시된대로 각 행 / 열에 들어가고 언제든지 0을 발견하면 부울 변수를 설정하고 해당 행 / 열을 다시 걸어서 항목을 0으로 설정하십시오.

추가 메모리가 필요하지 않으며 부울 변수는 하나만 사용합니다. 불행하게도, "먼"가장자리가 모두 0으로 설정되면, 최악의 경우이며 전체 배열을 두 번 걸어갑니다.


나는 틀릴 수 있지만 이것이 효과가 있습니까? 세 번째 열을 수행 할 때 첫 번째 행을 처리하기 전에 첫 번째 행의 맨 위에있는 값이 1인지 0인지 어떻게 알 수 있습니까?
Steve Jessop

당신은 모르지만, 또한 필요하지 않습니다. 0 인 경우 전체 열은 0이어야합니다. 이전 행의 값이 1 인 경우 그 위의 모든 행이 1 (항상 존재 했음)임을 알 수 있습니다.
Dave Sherohman

0

결과 행렬을 만들고 모든 값을 1로 설정하십시오. 0이 발생하자마자 데이터 행렬을 살펴보고 결과 행렬 행 열을 0으로 설정하십시오.

첫 번째 패스가 끝나면 결과 행렬에 정답이 있습니다.

꽤 단순 해 보입니다. 내가 놓친 트릭이 있습니까? 결과 집합을 사용할 수 없습니까?

편집하다:

F # 함수처럼 보이지만 단일 패스를 수행하더라도 함수가 재귀 적 일 수 있기 때문에 약간의 부정 행위입니다.

면접관이 함수형 프로그래밍을 알고 있는지 파악하려고하는 것 같습니다.


1
결과 집합을 사용하면 추가 메모리가 필요합니다.
cdeszaq

함수형 프로그래밍은 원래 배열을 수정하지 않습니다.
Svante

0

글쎄, 나는 4 개의 bool과 2 개의 루프 카운터를 사용하는 단일 패스, 인플레 이스 (비 재귀) 솔루션을 생각해 냈다. 나는 그것을 2 bools와 2 int로 줄이지 않았지만 가능하다면 놀라지 않을 것입니다. 각 셀의 약 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;
}

0

1 패스 C # 솔루션을 즐기시기 바랍니다.

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

유일한 문제는이 작업을 수행하기 위해 두 개의 추가 데이터 배열을 사용하고 있다는 것입니다. 규정 중 하나는 추가 메모리를 사용하지 않는 것입니다. 그러나 멋지다! 이것은 내가 :) 내 대답에 무슨 짓을했는지 기본적으로
케니 CASON

0

패스 1 개, 부울 2 개. 반복의 정수 인덱스는 계산하지 않는다고 가정해야합니다.

이것은 완전한 해결책은 아니지만이 시점을 통과 할 수는 없습니다.

0이 원래 0인지 또는 0으로 변환 된 1인지 확인할 수 있다면 -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와 높이를 확인하여 수행 각 반복에서 -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's at x and width - x positions. Halfway through I'll konw if there's a 0 in this row.
        //If a 0 is found set my first boolean to false.
        If x <= (Math.Ceiling((UBound(D) + 1) / 2) - 1) Then
            If D(x, y) = 0 Or D(UBound(D) - x, y) = 0 Then B1 = False
        End If

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

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

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

    Next
Next

0

아무도 이진 형식을 사용하고 있지 않습니까? 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

0

하나의 패스를 사용하고 입력 및 출력 매트릭스를 사용하려면 다음과 같이 할 수 있습니다.

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

col(xy)포인트를 포함하는 열의 비트는 어디에 있습니까 xy? row(xy)점을 포함하는 행의 비트입니다 xy. n행렬의 크기입니다.

그런 다음 입력을 반복하십시오. 더 공간 효율적으로 확장 할 수 있습니까?


0

하나의 매트릭스 스캔, 두 개의 부울, 재귀 없음.

두 번째 패스를 피하는 방법? 두 번째 패스는 0이 끝에 나타날 때 행이나 열을 지우는 데 필요합니다.

그러나 행 #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();
}

0

추가 공간이 필요하지 않은 다음과 같이 작동합니다.

먼저 행의 요소에 요소가있는 선의 요소를 곱하면 원하는 값이 제공됩니다.

추가 공간을 사용하지 않으려면 (새 행렬을 작성하지 않고 채우는 대신 직접 변경 사항을 행렬에 적용) 행렬의 왼쪽 상단을 시작하고 ixi 행렬 ((0에서 "시작")에 대한 계산을 수행하십시오. , 0)) 색인이있는 요소를 고려하기 전에> i.

이것이 효과가 있기를 바랍니다 (havent testet)


잘못된 것 같습니다. 행 0에 값이 하나만 있다고 가정하십시오. (0,0)에 설정 한 최종 값이 0이면 나중에 전체 행을 0으로 설정합니다. 반드시 정확한 것은 아닙니다. 원칙에 따라 동적 프로그래밍 스타일을 수행하려면 실제로 셀당 2 개의 값을 저장해야합니다.
Eyal Schneider

물론입니다. 두 개의 값을 저장하는 대신 세 번째 가능성 (예 : -1)을 사용하여 "오래된"행렬에서 1 인 셀을 의미하며 결국 0으로 대체됩니다. 물론, 절대적으로 사용해야합니다. 곱셈 후 값. 결국 모든 -1은 0으로 대체됩니다.
DFF

0

이것은 C ++의 다른 N에 대해 테스트 되었으며
ONE PASS , TWO BOOLS , NO RECURSION , NO EXTRA MEMORY , Arbortralyly Large N N에 대한 홀드
입니다.

더 구체적으로, 나는 두 개의 루프 카운터를 사용하는 것이 좋습니다. 나는 두 개의 const unsigned를 가지고 있는데, 가독성을 위해 매번 계산되지 않고 존재합니다. 외부 루프 간격은 [0, N]이고 내부 루프 간격은 [1, n-1]입니다. switch 문은 대부분 루프에 있으며 실제로 하나의 패스라는 것을 매우 명확하게 보여줍니다.

알고리즘 전략 :

첫 번째 요령은 행렬의 내용을 누적하기 위해 행렬 자체에서 행과 열을 만드는 것입니다.이 메모리는 첫 번째 행과 열에서 알아야 할 모든 것을 두 개의 부울로 오프로드하여 사용할 수 있습니다. 두 번째 요령은 하위 행렬과 그 인덱스의 대칭을 사용하여 하나에서 두 패스를 얻는 것입니다.

알고리즘 개요 :

  • 첫 번째 행을 스캔하고 모두 부울에있는 경우 저장하고 결과를 두 번째 부울에 저장하는 첫 번째 열에 대해 동일하게 수행하십시오.
  • 첫 번째 행과 첫 번째 열을 제외한 하위 행렬의 경우 : 단락을 읽을 때와 같이 왼쪽에서 오른쪽으로, 위에서 아래로 반복합니다. 각 요소를 방문하면 하위 행렬을 반대로 방문하면 방문 할 해당 요소도 방문합니다. 방문한 각 요소와 해당 값이 해당 행이 첫 번째 열과 교차하는 위치 및 해당 열과 첫 번째 행이 교차하는 위치의 값
  • 하위 행렬의 중심에 도달하면 위와 같이 두 요소를 동시에 계속 방문하십시오. 그러나 이제 방문한 요소의 값을 행이 첫 번째 열과 교차하는 위치와 열이 첫 번째 행과 교차하는 AND로 설정하십시오. 그런 다음 하위 행렬이 완료됩니다.
  • 구걸 할 때 계산 된 두 개의 부울 변수를 사용하여 첫 번째 행과 첫 번째 열을 올바른 값으로 설정하십시오.

템플릿 화 된 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;
}

0

좋아, 나는 그것이 일치하는 것이 아니라는 것을 알고 있지만 두 개의 bools 대신 bool과 1 바이트를 사용하여 한 번에 얻었습니다 ... 또한 그것의 효율성을 보증하지는 않지만 이러한 유형의 질문은 종종 최적의 솔루션보다 덜 필요합니다.

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

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

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

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

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

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

0

랜덤 액세스 순서로 매트릭스에 액세스하는 것을 계산하지 않으면 한 번에 정렬 할 수 있으므로 처음에 단일 패스 (캐시 일관성 / 메모리 대역폭)의 이점을 제거합니다.

[편집 : 간단하지만 잘못된 해결책이 삭제됨]

행 / 열 정보를 누적하는 방법과 적용하는 방법의 두 가지 방법으로 단일 패스 방법보다 성능이 향상됩니다. 배열은 (주요 순서대로) 일관되게 액세스됩니다. 캐시 크기를 초과하지만 행이 캐시에 들어갈 수있는 배열의 경우 메모리에서 데이터를 두 번 읽고 한 번 저장해야합니다.

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

0

내가 생각할 수있는 가장 간단한 해결책은 다음과 같습니다. 논리는 반복하는 동안 0을 설정할 행과 열을 기록하는 것입니다.

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

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

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

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

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

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

    }

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

0

다음은 테스트가 포함 된 Ruby 구현입니다 .O (MN) 공간이 필요합니다. 실시간 업데이트를 원한다면 (0을 찾는 첫 번째 루프를 기다리지 않고 0을 찾을 때 결과를 표시하는 것과 같이) 다른 클래스 변수를 만들 수 있습니다 .0 @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

0

아래 코드는 m, n 크기의 행렬을 만듭니다. 먼저 행렬의 치수를 결정하십시오. 나는 매트릭스 [m] [n]를 무작위로 0..10 사이의 숫자로 채우고 싶었다. 그런 다음 동일한 차원의 다른 행렬을 만들고 -1 (최종 행렬)로 채 웁니다. 그런 다음 초기 행렬을 반복하여 0에 도달하는지 확인합니다. location (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;
}

게시 한 코드에 대한 설명이나 컨텍스트를 제공하지 않습니다.
Aaron

이제 더 나아지기를 바랍니다. 경고 주셔서 감사합니다. 분명하지 않다면 더 설명하고 싶습니다.
user3743369

0

여기 내 해결책이 있습니다. 코드에서 볼 수 있듯이 M * N 행렬이 주어지면 행에서 0을 검사하면 전체 행을 0으로 설정합니다. 내 솔루션의 시간 복잡도는 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("");
    }

}

}

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.