Escolha a vara mais longa

13

Você é um jovem nerd de programação que vive com seus outros 2 melhores amigos. Toda semana, um de vocês tem que fazer todas as tarefas da casa e decide quem é a vez de escolher um pedaço de pau. Quem escolhe o menor palito perde e faz todas as tarefas.

Como todos vocês são programadores e adoram criar quebra-cabeças, você modificou o "Escolha o menor bastão" em um quebra-cabeça de computador.

Aqui estão as regras do quebra-cabeça.

  1. Você receberá uma matriz 2D, onde cada coluna representa um bastão.
  2. Em cada coluna, 1 representa uma parte do manche e 0 é um espaço vazio
  3. Ao passar de cima para baixo em cada coluna, inicialmente você tem 0e, assim que clicar em um 1, o stick é iniciado e o restante da coluna será preenchido 1apenas com
  4. Você pode escrever seu programa para escolher uma coluna. O tamanho do stick nessa coluna determina o vencedor / perdedor. Tamanho do stick == número de 1s nessa coluna.
  5. No entanto, esse programa pode ter apenas uma complexidade linear no pior dos casos.

Como todos vocês são programadores, saberão se o programa de outra pessoa está gravando o limite de complexidade de tempo.

Seu trabalho é:

  • Escreva um programa ou função que aceite entrada em formato 2D ou matriz de strings.
  • A entrada pode ser obtida no STDIN / prompt / console ou em um argumento de função.
  • Se você estiver lendo a entrada do STDIN / prompt, poderá presumir que a leitura da entrada e a conversão para uma matriz leva 0 tempo (mesmo que o código para fazê-lo precise estar presente na sua resposta)
  • Determine a coluna com o bastão mais longo.
  • A saída pode ser o valor de retorno da função ou para STDOUT / console / alerta.
  • O programa / função deve ter complexidade linear de pior caso, O(m+n)onde mé o número de linhas e no número de colunas.

A entrada pode ser um dos seguintes formatos:

Matriz 2D:

[ [0, 0, 0, 0],
  [1, 0, 0, 0],
  [1, 1, 0, 1],
  [1, 1, 1, 1] ]

Matriz de cordas:

[ "0000", "1000", "1101", "1111" ]

A entrada terá as seguintes propriedades:

  • O tamanho da matriz é desconhecido, assuma um retângulo de qualquer tamanho
  • Em qualquer coluna, de cima para baixo, se você vir 1, tudo abaixo será um
  • Paus de colunas vazias (ou seja, comprimento 0) são permitidos.

Este é um código de golfe, portanto o código mais curto vence ! *

Por favor, explique seu código ou forneça a versão simples (para verificar a complexidade do tempo) junto com qual dos dois formatos de entrada você espera.

ATUALIZAÇÃO Complexidade de tempo linear aqui significa O (n + m) em que n é o tamanho da coluna e m é o tamanho da linha. (Para aqueles que não estavam claros)

ATUALIZAÇÃO 2 Isso definitivamente pode ser feito em tempo linear. E se você estiver postando uma resposta, fique à vontade para adiar a publicação da lógica / algoritmo por alguns dias para uma luta justa :)

ATUALIZAÇÃO 3 Vou analisar todas as respostas em algumas horas para validar a complexidade do tempo e o programa :)

Optimizer
fonte
2
Eu argumentaria que isso não pode ser feito em O (n + m), pois cada célula pode conter o valor crucial (ou seja, o primeiro "1" da coluna / coluna mais longa). Então, você precisa olhar para cada célula, que recebe O (n * m).
Falko,
Poderia haver colunas vazias?
Martin Ender
@ Otimizador: Oh, entendo. Você está certo. :)
Falko
11
Não pode ser feito em O (n + m). Depois que a entrada é convertida em um formato que permite acesso aleatório, o processamento restante pode ser O (n + m), mas você precisa escrever um programa e, na pior das hipóteses, o único 1na entrada é a última célula. é necessário ler toda a entrada. Mesmo que a biblioteca padrão de uma linguagem falsifique o acesso aleatório ao stdin, nos bastidores ela está armazenando buffer e, portanto, o tempo gasto é Omega (n * m).
Peter Pan
2
Se você deseja permitir que as pessoas " simplesmente façam uma função que aceite uma matriz ", a pergunta não deve indicar que elas devem escrever um programa. E se você precisar de soluções que estejam em O (N ^ 0,5), em que N é o tamanho da entrada, não solicite soluções de tempo lineares. Uma solução de tempo linear pode ler toda a entrada.
Peter

Respostas:

4

GolfScript, 45 caracteres

:^,:y;0:x{^y(=x=2%y*{y(:y;x\}{x):x}if^0=,<}do

Recebe a entrada como uma matriz de seqüências de caracteres, retorna o índice (com base em 0) da coluna mais alta. Ele é executado nas iterações O ( linhas + colunas ), e cada iteração deve levar essencialmente tempo constante (pelo menos assumindo aritmética de tempo constante). As únicas operações de array / string executadas dentro do loop são pesquisas de elementos ( =) e o comprimento de uma string ( ,), ambas com tempo constante no GolfScript.

Experimente online.

Explicação:

Como a maioria das soluções aqui, esse código funciona iniciando no canto inferior esquerdo da matriz, avançando para cima ou para a direita, dependendo se o elemento atual da matriz é 1 ou 0, e acompanhando a coluna onde foi movida pela última vez .

No início do programa, atribuo a matriz de entrada à variável ^, seu comprimento (ou seja, o número de linhas) ye de 0 a x. O valor 0 também é deixado na pilha; durante o loop a seguir, ele será substituído pelo índice da coluna mais alta.

No loop principal, ^y(=x=extrai o xcaractere y-1-th da linha -th em ^. Na verdade, isso retorna o código ASCII do caractere; portanto, 2%é necessário descartar tudo, exceto o último bit. Como um caso especial, se for yigual a 0 (o que pode acontecer se a coluna mais alta encontrada até agora chegar até a linha superior), o bit procurado na verdade virá da última linha da matriz (índice -1), mas o seguinte y*força a zero, criando efetivamente uma linha virtual com todos os zeros na parte superior da matriz.

A seguir, ifserá executado um dos dois blocos de código que o precede, dependendo se o bit pesquisado for diferente de zero (verdadeiro) ou zero (falso). Se diferente de zero, yé decrementado por um, e o valor atual de xsubstitui o índice de coluna mais alto da pilha (com o valor antigo temporariamente deixado em cima). Se zero, xé simplesmente incrementado por um (e temporariamente deixado na pilha, no topo do índice de colunas mais alto).

Por fim, ^0=extrai a primeira linha da matriz, ,retorna seu comprimento e a <compara com o índice da coluna temporariamente deixado na pilha (que será igual xse apenas tiver sido incrementado). Se o índice for menor que o comprimento da linha, o loop repete.

Ps. Com base nos meus testes, deve ser possível reduzir esse programa em um caractere, substituindo o teste de comprimento da string ,<no final do loop por >, que corta a string no índice especificado e retorna a parte final (que estará vazia e portanto, falso, no final do loop). No entanto, enquanto cortar uma string como essa parece ser implementado como uma operação de tempo constante no GolfScript (ou melhor, no Ruby, que o GolfScript executa sobre), não encontrei nenhuma documentação oficial dizendo isso. Apenas para garantir, escolhi a versão um pouco mais longa, mas definitivamente a versão O (1) acima.

Ilmari Karonen
fonte
6

Ruby, 83 75 68 66 63 bytes

f=->m{m[b=c=i=0].map{(c=i;b-=1)while(r=m[b-2])&&r[i]>0;i+=1};c}

Define uma função fque assume o formato de matriz 2D como entrada.

Estou começando no canto inferior esquerdo, acompanhando o comprimento máximo do manche (na verdade, menos isso) e a coluna correspondente. Em cada coluna, se ainda houver 1s acima do comprimento máximo anterior do bastão, subo o bastão até o fim e lembro do novo comprimento e coluna máximos. Isso significa que eu estou iterando uma vez ao longo das colunas e no máximo uma vez ao longo das linhas (especificamente eu estou iterando até o comprimento máximo do stick), o que é precisamente O(m+n).

Martin Ender
fonte
@Optimizer Não vi sua segunda edição até depois da publicação, portanto estava no histórico de edição. É por isso que eu coloco isso em um spoiler para as pessoas que querem descobrir por si mesmas.
Martin Enders
4

Python 2-71, 69, 73, 75 81

j=i=-1
M=input()
for m in M[0]:
 j+=1
 while-i<len(M)and M[i][j]:i-=1;J=j
print J
Falko
fonte
Pretende ser executado em Python 2 ou 3? Como deve ser a entrada?
feersum
1
@feersum Python 2, a matriz de matrizes.
Justin
@feersum: Quincunx está certo. A entrada é uma matriz 2D de entradas, como você sugeriu.
Falko
Não isairá dos limites se um bastão ocupar uma coluna inteira?
xnor
1
Desculpe, mas parece que mudar jpara contar de 0quebra a condição do loop i*j.
Xnor
2

C, 64 bytes

Edit: eu aprendi que a pergunta pede a localização da coluna mais longa e não o seu comprimento.

A primeira linha é o código de golfe e o restante é a invocação de amostra.

g(int m,int n,int**a,int*r){for(*r=n;n*m;a[m][n]?m--,*r=n:--n);}

/* usage:
    m = number of rows
    n = number of columns
    a = 1-based 2D array such that a[i][j] gives the value at the ith row and jth column
    r = address of return value 
    Returns (to r) the 1-indexed location of a column with the longest length, or 0 if n=0
    */

int main()
{
    int flat[4*4] = {1, 0, 0, 0,
                     1, 0, 0, 1,
                     1, 1, 0, 1,
                     1, 1, 1, 1};
    int*twoD[4] = {flat-1,flat+3,flat+7,flat+11};
    int ret;
    g(4,4,twoD-1,&ret);
    printf("%d", ret);
    return 0;
}

// old function which determines longest length (65 bytes)
f(int m,int n,int**a,int*r){for(*r=m;n*m;a[m][n]?m--:--n);*r-=m;}
feersum
fonte
Impressionante! Você pode abandonar os ints na assinatura da função por acaso ou isso não funciona devido aos ponteiros lá?
Martin Ender
1
A entrada deve conter apenas a matriz. Você não pode informar o programa sobre o tamanho da matriz.
Optimizer
Espere, isso realmente funciona? Este parece estar voltando ao comprimento da vara mais longa e não sua posição: ideone.com/YEzqzl
Martin Ender
2
@Optimizer que é basicamente impossível em C.
Martin Ender
Pode ser, mas essa é a questão :)
Optimizer
2

C #: 236 caracteres

int p(int[,] a){int y=0,s=0,i=0,x;for(;++y<=a.GetUpperBound(0);)for(x=i;x<=a.GetUpperBound(1);){if(a[y,x++]==0)break;s=y;i++;}return s;}

ungolfed:

int p(int[,] a)
{
    int selectedRow=0;
    int maxLength=0;
    for(var y = 0; y<=a.GetUpperBound(0); y++)
        for(var x=maxLength; x<=a.GetUpperBound(1); x++)
        {
            if(a[y,x++]==0)
                break;
            selectedRow=y;
            maxLength++;
        }
    return selectedRow;
}
Stephan Schinkel
fonte
2

PHP 5.4 - 108 bytes

(113 se você incluir o <?php)

Formato de entrada: a matriz será lida como uma sequência JSON.

php longest_stick.php "[[0, 0, 0, 0],[1, 0, 0, 0],[1, 1, 0, 1],[1, 1, 1, 1]]"

Espaço em branco adicionado para facilitar a leitura - todas as novas linhas e espaços à esquerda podem ser removidos.

<?php
$t=count($s=json_decode($argv[1]))-1;
foreach($s[0] as $k=>$_)
    while($s[$t][$k]) {
        $t--;
        $l = $k;
    }
echo $l?:0;

Versão reduzida:

<?php $t=count($s=json_decode($argv[1]))-1;foreach($s[0] as $k=>$_)while($s[$t][$k]){$t--;$l=$k;}echo $l?:0;

Tipo de roubar o algoritmo de Martin aqui, mas é bom brincar com linguagens que não são vistas com tanta frequência aqui XD

Niet, o Escuro Absol
fonte
@ MartinBüttner "Roubei" seu algoritmo, então deve ser O (n + m) agora. Eu acho que está certo XD
Niet the Dark Absol
Você pode substituir $s=json_decode($argv[1]);$t=count($s)-1;por $t=count($s=json_decode($argv[1]))-1;(-3 bytes).
Blackhole
@ Blackhole Na verdade, você pode. Obrigado!
Niet the Dark Absol
@ Blackhole Eu acho que isso quebraria a funcionalidade. Ele executará as atribuições mesmo que a condição não seja atendida.
Niet the Dark Absol
@Blackhole Ainda o quebra, receio que o XD $t--só aconteça se a condição for atendida.
Niet the Dark Absol
2

Cobra - 98

def f(a)
    s,x,y=0,0,a.count-1
    while y+1and x<a[0].count
        while a[y][x],y,s=y-1,x
        x+=1
    print s
Furioso
fonte
2

C ++ :: 78

Diferente da outra solução C, este é o programa inteiro. (nenhuma chamada é necessária, não há necessidade de informar à função o tamanho da matriz). Infelizmente, isso significa que é mais longo, pois maindeve ser usado, em vez de um único nome de função de caractere. Tenho que interpretar a entrada e, em seguida, enviar a resposta, onde a outra solução lida com isso "em outro lugar". Também meu primeiro código de golfe.
compilado com g++ file.cpp -include iostream, executado com ./a 000 010 110 111(por exemplo) == matriz de strings (acredito que isso seja permitido na pergunta)

int c;main(int r,char**v){for(r--;r*v[r][c];v[r][c]-48?std::cout<<c,r--:++c);}

A versão acima gera o melhor atual encontrado até agora em cada iteração. O dígito final de saída é a resposta. A mudança do processamento da parte inferior esquerda em vez da parte inferior direita e a 0indexação reduziram essa solução em 10 (!) Caracteres.
mudar para c ++ reduz o envio de mais um caractere, pois std::cout<<é mais curto putchar(-48)e também deve suportar explicitamente mais de 9 varas com saída adequada (embora possa ser mais difícil diferenciar cada saída) A
remoção do campo de resposta e a saída cortam diretamente outros 6 caracteres. Agora, ele só produz a melhor corrente quando sobe, o que elimina, pelo menos, parte da produção.
O arquivo inteiro agora tem apenas 78 bytes de tamanho - aproximando-se da solução de função única que o outroCusos de envio. (com muito código extra para dar suporte à referida função).

Como a descrição abaixo está desatualizada:

cé global, portanto, é inicializado com 0
ro número de entradas (linhas) +1 (nome do programa)
vé a matriz de cadeias que v[0]é inválida (nome do programa)
Como é 0 indexado, restá fora dos limites, portanto diminua.
Enquanto r!=0(apontando para cadeia válida) e caráter cna cadeia não é o terminador nulo '\0'
se o personagem não '0' é
ir até uma linha ( r) e saída da coluna ( c)
então ir para a próxima coluna ( c)

feito

Posso jogar golfe ainda mais?

Código não jogado (com saída extra):

#include <stdio.h>
#include <string.h>

int main(int argc, char* argv[])
{
  int rows = argc-1;
  int cols = strlen(argv[1]);
  int ans;

  printf("rows: %d, cols: %d\n",rows, cols);

  while((rows)&&cols)
  {
    if (argv[rows][cols-1]-'0')
    {
      printf("stick @%d,%d\n",cols,rows);
      ans = cols;
      rows--;
    }
    else
    {
      printf("no stick @%d,%d\n",cols,rows);
      cols--;
    }
  }
  printf("%d",ans);
}
Ele usa o comprimento das strings para descobrir o número de colunas e argc para encontrar o número de linhas. Começando no canto inferior direito, segue estas regras simples: Se a célula for um bastão, mova para cima e defina a resposta para a coluna atual. Se a célula não for uma vara, mova-se para a esquerda. O (n + m): como só se move para cima e para a esquerda, ele pode ter no máximo n + m leituras. Ele sai mais cedo se cair da parte superior ou esquerda da matriz.

Baldrickk
fonte
1

OCaml - 144 caracteres

let s a=Array.(let rec f i j m=if i=0then m else if a.(i).(j)=0then if j=length a.(i)-1then m else f i(j+1)m else f(i-1)j j in f(length a-1)0 0)

Toma uma int array arrayentrada como e começa a partir de baixo à esquerda, movendo-se para cima ou para a direita se vir a 1ou a 0. A contagem de colunas começa em 0.

Uso

 s [| [| 0; 0; 0; 0 |]; [| 0; 0; 1; 0|]; [| 1; 0; 1; 0 |]; [| 1; 1; 1; 0 |]; [| 1; 1; 1; 1 |] |];;
 - : int = 2

Ungolfed

let s a = Array.(
  let rec f i j m = (* m is the longest stick seen so far *)
    if i=0 then m (* A column is full: this is the longest possible stick and j=m anyway *)
    else if a.(i).(j)=0 then (* current column is shorter than a previously seen stick *)
      if j=length a.(i)-1 then m (* we have examined all columns, just return m *)
      else f i(j+1) m (* start examining next column *)
    else f (i-1) j j (* current column is longer than all the ones previously seen. Check how long the stick is *)
  in
  f (length a-1) 0 0)
Virgile
fonte
0

T-SQL - 71 64

Toma a tabela A como entrada

SELECT IDENTITY(INT, 1, 1) R, A INTO A
FROM (VALUES
 ('0000')
,('1000')
,('1101')
,('1111')
) AS A(A)

E a consulta é

SELECT TOP(1)CHARINDEX('1',A)FROM A WHERE A LIKE'%1%' ORDER BY R

SQLFiddle

Isso retorna a primeira linha da tabela a ordenada por r, onde existe um 1 na sequência a.

TOP(1) restringe o resultado à primeira linha retornada.

CHARINDEX('1',A) retorna a posição do primeiro 1 na string ou zero se não for encontrado.

WHERE A LIKE'%1%' filtra para linhas onde A contém um 1

ORDER BY R garante que a tabela seja lida de cima para baixo

MickyT
fonte
Você pode explicar o que está acontecendo nesse código? : D Nenhuma experiência com T-SQL
Optimizer
Entendo, então a filtragem em cada parte da linha não é uma operação O (n * m)? isto é, complexidade linear não temporal.
Optimizer
Difícil de dizer. O mecanismo SQL verificará todas as linhas para um 1 na coluna. Ele retornará apenas a primeira linha de cima para baixo qualificada. Portanto, nessa situação, ele varre a tabela inteira. Filtra as linhas com a coluna que contém 1. Classifica os resultados na coluna de identidade e retorna o primeiro resultado.
MickyT
Veja da seguinte forma: E se suas linhas forem como "0000", "0000", "0000", "0001". Nesse caso, ele terá que ir até a última linha e até o último caractere da linha para descobrir a presença de 1
Optimizer
1
Então sim, é O (m * n), então :) :)
Optimizer
0

Delphi 122 chars

Suspiro ... é uma linguagem tão volumosa.

Atualização: teve que adicionar 6 caracteres na função de alteração do tipo de retorno de I para inteiro. A função ainda compilada como o programa de teste tinha um "tipo I = inteiro;" sobra de uma versão anterior do programa.

function S(A:array of string):integer;var n,c:integer;begin n:=0; repeat c:=Pos('1',A[n]);inc(n) until c>0; result:=c;end;
Penguino
fonte
Você está fazendo a chamada Pos () em cada linha (no seu caso, string) da matriz?
Optimizer
@ Otimizador Sim, o programa pesquisa cada string na matriz (usando 'inc (n)') até encontrar um '1'. O primeiro '1' encontrado será o mais alto (ou o mais alto) '1'; portanto, sua posição na string (as strings são 1-ndexadas em delphi) será a posição da coluna mais longa. A rotina falha se não houver '1s na matriz, mas acredito que isso seria uma entrada quebrada, pois não haveria um "stick mais longo" a ser encontrado.
Penguino
1
Então, primeiro de tudo, esta é uma entrada válida: "0000", "0010", "1111"Em segundo lugar, a sua resposta não está a cumprir o requisito de complexidade de tempo linear
Optimizer
@Optimizer Sim, isso seria uma entrada válida e identifica corretamente o terceiro stick. Mas, depois de postar, percebi que havia convertido meu programa N de pedido válido que usava matrizes, em um programa N ^ 2 de pedido inválido que usava cadeias de caracteres (buscando uma redução de ~ 160 caracteres).
Penguino
0

esquema - 236 caracteres

Ainda mais que a versão delphi ... provavelmente existe uma maneira de fazer isso de maneira muito mais eficiente com o esquema. E pior ainda - acabei de notar que é a ordem m * n.

(define (s l) (cond ((eq? (cdr l) '()) (car l)) (else (map + (car l) (s (cdr l)))))) (define (u l) (define (t n p q l) (cond ((eq? l '()) p) ((< n (car l)) (t (car l) q (+ 1 q) (cdr l))) (else (t n p (+ 1 q) (cdr l))))) (t 0 0 1 (s l)))

l é uma lista da forma '((0 0 0 0) (1 0 0 0) (1 1 0 1) (1 1 1 1)). Eu acho que é uma representação justa de uma entrada de matriz 2D para o esquema.

(sl) soma os n-ésésimos elementos de cada uma das sub-listas de uma lista de listas de números, portanto (s '((0 0 0 0) (1 0 0 0) (1 0 0 0) (1 1 0 1) (1 1 1 1))) retornaria (3 2 1 2).

(ul) retorna o 'índice' da maior entrada de uma lista de números (usando a função auxiliar t), portanto (u '(3 2 1 2)) retornará 1 (como o maior elemento' 3 na lista ' (3 2 1 2) está na posição 1).

Penguino
fonte
A soma de todas as sublistas é uma operação O (m * n).
Martin Ender
0

Raquete 70

Golfe:

(define(h m)(for/last([r m]#:final(memv 1 r))(length(takef r even?))))

Assume que a entrada é uma matriz bidimensional, que em Racket seria uma lista de listas:

(define m 
  '((0 0 0 0)
    (1 0 0 0)
    (1 1 0 1)
    (1 1 1 1)))

Ungolfed:

(define (h m)
  ;; step through rows, stopping at the first that contains a 1
  (for/last ([r m] #:final (memv 1 r)) 
    (length (takef r even?)))) ; pop off the leading zeroes to get the column index

Retorna o índice da coluna com o stick mais longo.

Matthew Butterick
fonte
Então, basicamente, você está passando por cada coluna e contando o número de 1's?
Optimizer
Eu entendo o seu ponto. Algoritmo atualizado.
Matthew Butterick
Isso ainda tem uma complexidade de pior caso de O (m * n) (para o caso em que não há 1na matriz ou apenas na linha inferior).
Martin Ender
0

JavaScript, ES6, 76 caracteres

W=a=>(j=>{for(k=i=a.length-1;~i&~j;)a[i][j]?(k=j,i--):j--})(a[0].length-1)|k

Toma matriz de entrada da matriz.

Optimizer
fonte
0

JavaScript ES6, 65 bytes

Toma ambos os formatos de entrada

f=(a,t)=>a.reduceRight((p,c)=>t+1?t:(x=c.indexOf(1,p))+1?x:t=p,0)

Explicado:

Repete de baixo para cima. Usa String.prototype.indexOf()ou Array.prototype.indexOf()depende da entrada em cada valor. Localiza o primeiro índice de cada linha com 1 do deslocamento anterior; se não encontrar nenhum, define a tvariável para o último deslocamento e não realiza mais indexOfchamadas.

George Reith
fonte
indexOffunciona em qualquer O(log n)ou O(n), então o algoritmo geral nunca estarão emO(m + n)
Optimizer
@Otimizador Sim percebi que era o seu O (m * n) não estava pensando direito.
George Reith
@Optimizer Atualizado para serO(m+n)
George Reith