Dada uma matriz NxN com 0s e 1s. Defina todas as linhas que contêm a 0
para todos os 0
s e defina todas as colunas que contenham a 0
para todos os 0
s.
Por exemplo
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
resulta em
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
Um engenheiro da Microsoft me disse que existe uma solução que não envolve memória extra, apenas duas variáveis booleanas e uma passagem, por isso estou procurando por essa resposta.
BTW, imagine que seja uma matriz de bits, portanto, apenas 1s e 0s são permitidos na matriz.
algorithm
optimization
puzzle
jaircazarin-old-account
fonte
fonte
Respostas:
Ok, estou cansado porque são 3 da manhã aqui, mas tenho uma primeira tentativa com exatamente 2 passagens em cada número na matriz, então em O (NxN) e é linear no tamanho da matriz.
Eu uso a primeira coluna e a primeira linha como marcadores para saber onde estão as linhas / colunas com apenas 1. Então, existem 2 variáveis le c para lembrar se a primeira linha / coluna também é 1. Portanto, o primeiro passe define os marcadores e redefine o restante para os zero.
A segunda passagem define 1 em locais onde as linhas e colunas foram marcadas como 1 e redefine a 1ª linha / coluna, dependendo de le c.
Duvido muito que possa ser feito em 1 passe, pois os quadrados no início dependem dos quadrados no final. Talvez meu segundo passe possa ser mais eficiente ...
fonte
Isso não pode ser feito em uma única passagem, pois um único bit afeta os bits antes e depois em qualquer ordem. IOW Qualquer que seja a ordem em que você atravessa a matriz, mais tarde você pode encontrar um 0, o que significa que você precisa voltar e alterar um 1 anterior para um 0.
Atualizar
As pessoas parecem pensar que, restringindo N a algum valor fixo (por exemplo, 8), você pode resolver esse é um passo. Bem, isso é a) não entender o assunto eb) não a questão original. Eu não postaria uma pergunta sobre classificação e esperaria uma resposta que começou "supondo que você queira classificar apenas 8 coisas ...".
Dito isto, é uma abordagem razoável se você souber que N é de fato restrito a 8. Minha resposta acima responde à pergunta original que não tem essa retribuição.
fonte
Então, minha ideia é usar os valores na última linha / coluna como um sinalizador para indicar se todos os valores na coluna / linha correspondente são 1s.
Usando uma varredura em Zig Zag em toda a matriz, EXCETO a linha / coluna final. Em cada elemento, você define o valor na linha / coluna final como o AND lógico de si mesmo com o valor no elemento atual. Em outras palavras, se você acertar 0, a linha / coluna final será definida como 0. Se você for 1, o valor na linha / coluna final será 1 somente se já fosse 1. De qualquer forma, defina o elemento atual como 0.
Quando você terminar, sua linha / coluna final deverá ter 1s se a coluna / linha correspondente for preenchida com 1s.
Faça uma varredura linear na linha e coluna finais e procure por 1s. Defina 1s nos elementos correspondentes no corpo da matriz em que a linha e a coluna finais são 1s.
A codificação será complicada para evitar erros de um por um, etc., mas deve funcionar de uma só vez.
fonte
Eu tenho uma solução aqui, ela é executada em uma única passagem e faz todo o processamento "no local" sem memória extra (exceto para aumentar a pilha).
Ele usa recursão para atrasar a gravação de zeros, o que naturalmente destruiria a matriz para as outras linhas e colunas:
fonte
Eu não acho que é factível. Quando você está no primeiro quadrado e seu valor é 1, não há como saber quais são os valores dos outros quadrados na mesma linha e coluna. Portanto, você deve verificar esses itens e, se houver um zero, retorne ao primeiro quadrado e altere seu valor para zero. Eu recomendo fazer isso em duas passagens - a primeira passagem reúne informações sobre quais linhas e colunas devem ser zeradas (as informações são armazenadas em uma matriz, por isso estamos usando memória extra). A segunda passagem altera os valores. Sei que essa não é a solução que você está procurando, mas acho que é prática. As restrições dadas por você tornam o problema insolúvel.
fonte
Eu posso fazer isso com duas variáveis inteiras e duas passagens (até 32 linhas e colunas ...)
fonte
~
inverte todos os bits em uma variável. 0x00000000 passa a 0x00000000. Basicamente, começo com todos e limpo o bit para uma linha / coluna quando encontro um 0. CompleteCols possui os bits 2 e 3 configurados e CompleteRows possui os bits 2 e 4 configurados (com base em 0).o problema pode ser resolvido de uma só vez
salvando a matriz em uma matriz i X j.
agora imprima todos os valores como 0 para os valores de iej salvos em a e b, o restante dos valores é 1, isto é, (3,3) (3,4) (5,3) e (5,4)
fonte
Outra solução que leva duas passagens é acumular ANDs horizontal e verticalmente:
Eu pensei que poderia projetar esse algoritmo usando bits de paridade , códigos de Hamming ou programação dinâmica , possivelmente usando esses dois booleanos como um número de 2 bits, mas ainda não obtive sucesso.
Você pode verificar novamente a declaração do problema com seu engenheiro e nos informar? Se não é realmente uma solução, eu quero manter desbastando o problema.
fonte
Mantenha uma única variável para acompanhar o que são todas as linhas AND juntas.
Se uma linha for -1 (todos os 1s), faça da próxima linha uma referência a essa variável
Se uma linha é qualquer coisa, mas é 0. Você pode fazer tudo de uma só vez. Código Psuedo:
Isso deve ser feito em uma única passagem - mas há uma suposição aqui de que N é pequeno o suficiente para que a CPU faça aritmética em uma única linha; caso contrário, você precisará fazer um loop sobre cada linha para determinar se está tudo 1s ou não, acredito. Mas, como você está perguntando sobre algos e não restringindo meu hardware, eu começaria minha resposta com "Construa uma CPU que suporte aritmética de N bits ..."
Aqui está um exemplo de como isso pode ser feito em C. Observe que eu argumento que valores e arr juntos representam a matriz, e p e numproduct são meus iteradores e variáveis de produto AND usados para implementar o problema. (Eu poderia ter repetido arr com aritmética de ponteiro para validar meu trabalho, mas já foi o suficiente!)
Isso produz 0, 0, 6, 0, 6, que é o resultado para as entradas fornecidas.
Ou no PHP, se as pessoas pensam que meus jogos de pilha em C estão trapaceando (sugiro que não seja, porque devo poder armazenar a matriz da maneira que quiser):
Estou esquecendo de algo?
fonte
Belo desafio. Essa solução usa apenas dois booleanos criados na pilha, mas os booleanos são criados várias vezes na pilha, pois a função é recursiva.
Isso digitaliza em um padrão como:
e assim por diante
E, em seguida, alterar os valores nesse padrão no retorno de cada uma das funções de varredura. (Debaixo para cima):
e assim por diante
fonte
Ok, esta é uma solução que
fonte
Na realidade. Se você deseja apenas executar o algoritmo e imprimir os resultados (ou seja, não restaurá-los, isso pode ser feito facilmente de uma só vez. O problema ocorre quando você tenta modificar a matriz enquanto executa o algoritmo.
Aqui está minha solução: envolve apenas ANDing dos valores de linhas / colunas para um elemento de givein (i, j) e imprimindo-o.
fonte
Eu tentei resolver esse problema em c #.
Eu usei duas variáveis de loop (iej) além da matriz real en representando sua dimensão
A lógica que tentei é:
Código:
fonte
Uma passagem - eu percorri a entrada apenas uma vez, mas usei uma nova matriz e apenas duas variáveis booleanas extras.
fonte
Embora impossível, dadas as restrições, a maneira mais eficiente em termos de espaço é atravessar a matriz de maneira alternada de linha / coluna, sobrepostas, o que criaria um padrão semelhante ao assentamento de tijolos em zigue-zague:
Usando isso, você entraria em cada linha / coluna, conforme indicado, e se encontrar um 0 a qualquer momento, defina uma variável booleana e ande novamente nessa linha / coluna, definindo as entradas como 0 à medida que avança.
Isso não exigirá memória extra e usará apenas uma variável booleana. Infelizmente, se a borda "distante" estiver definida como 0, esse é o pior caso e você percorrerá toda a matriz duas vezes.
fonte
crie uma matriz de resultados e defina todos os valores como 1. passe pela matriz de dados assim que um 0 for encontrado, defina a coluna da linha da matriz de resultados como 0
No final da primeira passagem, a matriz de resultados terá a resposta correta.
Parece bem simples. Há um truque que estou perdendo? Você não tem permissão para usar um conjunto de resultados?
EDITAR:
Parece uma função F #, mas isso está enganando um pouco, pois mesmo que você esteja executando uma única passagem, a função pode ser recursiva.
Parece que o entrevistador está tentando descobrir se você conhece programação funcional.
fonte
Bem, eu vim com uma solução de passagem única no local (não recursiva) usando 4 bools e 2 contadores de loop. Não consegui reduzi-lo para 2 bools e 2 ints, mas não ficaria surpreso se fosse possível. Faz cerca de 3 leituras e 3 gravações de cada célula, e deve ser O (N ^ 2), ie. linear no tamanho da matriz.
Demorei algumas horas para resolver este problema - eu não gostaria de ter que pensar nisso sob a pressão de uma entrevista! Se eu fiz um booboo, estou cansado demais para vê-lo ...
Hum ... estou escolhendo definir "passagem única" como fazer uma varredura pela matriz, em vez de tocar em cada valor uma vez! :-)
fonte
Espero que você goste da minha solução c # de 1 passagem
você pode recuperar um elemento com O (1) e precisa apenas do espaço de uma linha e uma coluna da matriz
fonte
1 passe, 2 booleanos. Eu só tenho que assumir que os índices inteiros nas iterações não contam.
Esta não é uma solução completa, mas não consigo passar neste ponto.
Se eu pudesse determinar se um 0 é um 0 original ou um 1 que foi convertido em um 0, não precisaria usar -1 e isso funcionaria.
Minha saída é assim:
A originalidade da minha abordagem é usar a primeira metade do exame de uma linha ou coluna para determinar se ela contém 0 e a última metade para definir os valores - isso é feito observando xe largura-xe depois y e altura -y em cada iteração. Com base nos resultados da primeira metade da iteração, se um 0 na linha ou coluna foi encontrado, eu uso a última metade da iteração para alterar os 1s para -1s.
Acabei de perceber que isso poderia ser feito com apenas 1 booleano deixando 1 para ...?
Estou postando isso esperando que alguém possa dizer: "Ah, faça isso ..." (E eu gastei muito tempo para não postar).
Aqui está o código no VB:
fonte
Ninguém está usando formulários binários? como são apenas 1 e 0. Podemos usar vetores binários.
Aqui está o teste:
E a saída:
fonte
Você pode fazer algo assim para usar uma passagem, mas uma matriz de entrada e saída:
onde
col(xy)
estão os bits na coluna que contém o pontoxy
;row(xy)
são os bits na linha que contêm o pontoxy
.n
é o tamanho da matriz.Em seguida, basta fazer um loop sobre a entrada. Possivelmente expansível para ser mais eficiente em termos de espaço?
fonte
Uma varredura matricial, dois booleanos, sem recursão.
Como evitar o segundo passe? A segunda passagem é necessária para limpar as linhas ou colunas quando o zero aparecer no final.
No entanto, esse problema pode ser resolvido porque, quando examinamos a linha #i, já sabemos o status da linha # i-1. Portanto, enquanto estivermos varrendo a linha #i, podemos limpar simultaneamente a linha # i-1, se necessário.
A mesma solução funciona para colunas, mas precisamos varrer linhas e colunas simultaneamente enquanto os dados não são alterados na próxima iteração.
Dois booleanos são necessários para armazenar o status da primeira linha e da primeira coluna, porque seus valores serão alterados durante a execução da parte principal do algoritmo.
Para evitar adicionar mais booleanos, estamos armazenando o sinalizador "clear" para as linhas e colunas na primeira linha e coluna da matriz.
fonte
parece que o seguinte funciona sem requisitos adicionais de espaço:
primeira nota que multiplicar os elementos da linha vezes os elementos da linha em que um elemento está, fornece o valor desejado.
Para não usar espaço adicional (não criando uma nova matriz e preenchendo-a, mas aplicando alterações diretamente na matriz), inicie o canto superior esquerdo da matriz e faça o cálculo para qualquer matriz ixi (que "começa" em (0 , 0)) antes de considerar qualquer elemento com qualquer índice> i.
espero que isso funcione (havent testet)
fonte
Esta é TESTADO para N diferente em C ++, e é:
One Pass , DOIS BOOLS , NO RECURSÃO , NO memória extra , vale para ARBITRARLY GRANDE N
(Até agora, nenhuma das soluções aqui fazer tudo isso.)
Mais especificamente, estou divertido dois contadores de loop estão bem. Eu tenho duas const assinadas, que existem apenas ao invés de serem computadas todas as vezes para facilitar a leitura. O intervalo do loop externo é [0, N] e o intervalo do loop interno é [1, n - 1]. A declaração switch está no loop principalmente para mostrar muito claramente que é realmente apenas uma passagem.
Estratégia de algoritmo:
O primeiro truque é para nós uma linha e uma coluna da própria matriz para acumular o conteúdo da matriz; essa memória fica disponível ao descarregar tudo o que realmente precisamos saber da primeira linha e coluna em dois booleanos. O segundo truque é obter duas passagens de uma, usando a simetria da sub-matriz e seus índices.
Sinopse do algoritmo:
Implementação C ++ modelo:
fonte
Ok, percebo que não é exatamente uma correspondência, mas consegui de uma só vez usando um bool e um byte em vez de dois bools ... perto. Eu também não atestaria a eficiência, mas esses tipos de perguntas geralmente exigem soluções abaixo do ideal.
fonte
Você pode fazer isso de uma só vez - se não contar acessando a matriz em ordem de acesso aleatório, o que elimina os benefícios de fazer uma única passagem em primeiro lugar (coerência de cache / largura de banda de memória).
[editar: solução simples, mas errada, excluída]
Você deve obter um desempenho melhor do que qualquer método de passagem única, fazendo-o em duas passagens: uma para acumular informações de linha / coluna e outra para aplicá-las. A matriz (na ordem principal da linha) é acessada de forma coerente; para matrizes que excedem o tamanho do cache (mas cujas linhas podem caber no cache), os dados devem ser lidos na memória duas vezes e armazenados uma vez:
fonte
A solução mais simples que consigo pensar é colada abaixo. A lógica é registrar qual linha e coluna definir zero durante a iteração.
fonte
Aqui está minha implementação do Ruby com o teste incluído. Isso ocuparia espaço O (MN). Se queremos uma atualização em tempo real (gostamos de mostrar os resultados quando encontramos zeros em vez de esperar o primeiro ciclo de encontrar zeros), podemos apenas criar outra variável de classe como
@output
e sempre que encontrarmos um zero, atualizamos@output
e não@input
.fonte
O código abaixo cria uma matriz de tamanho m, n. Primeiro decida as dimensões da matriz. Eu queria preencher a matriz [m] [n] aleatoriamente com números entre 0..10. Em seguida, crie outra matriz das mesmas dimensões e preencha-a com -1s (matriz final). Em seguida, percorra a matriz inicial para ver se você atingirá 0. Quando você atingir o local (x, y), vá para a matriz final e preencha a linha x com 0s e a coluna y com 0s. No final, leia a matriz final, se o valor for -1 (valor original), copie o valor no mesmo local da matriz inicial para final.
fonte
aqui está a minha solução. Como você pode ver no código, dada uma matriz M * N, ela define a linha inteira como zero quando inspeciona um zero nessa linha. A complexidade de tempo da minha solução é O (M * N). Estou compartilhando toda a classe que possui uma matriz preenchida estática para teste e um método de matriz de exibição para ver o resultado no console.
}
fonte