Eu quero escrever uma função que leva uma matriz de letras como argumento e um número dessas letras para selecionar.
Digamos que você forneça uma matriz de 8 letras e deseje selecionar 3 delas. Então você deve obter:
8! / ((8 - 3)! * 3!) = 56
Matrizes (ou palavras) em troca consistindo em 3 letras cada.
algorithm
combinations
ique
fonte
fonte
Respostas:
Arte da programação de computadores Volume 4: Fascículo 3 tem uma tonelada dessas que podem se encaixar melhor em sua situação específica do que a que eu descrevo.
Códigos Cinzentos
Um problema que você encontrará é a memória e, rapidamente, você terá problemas em 20 elementos em seu conjunto - 20 C 3 = 1140. E se você quiser percorrer o conjunto, é melhor usar um cinza modificado algoritmo de código para que você não esteja mantendo todos eles na memória. Eles geram a próxima combinação da anterior e evitam repetições. Existem muitos deles para diferentes usos. Queremos maximizar as diferenças entre combinações sucessivas? minimizar? et cetera.
Alguns dos documentos originais que descrevem códigos em cinza:
Aqui estão alguns outros artigos que abordam o tópico:
Chase's Twiddle (algoritmo)
Phillip J Chase, ` Algoritmo 382: Combinações de M de N Objetos '(1970)
O algoritmo em C ...
Índice de combinações em ordem lexicográfica (algoritmo de curvatura 515)
Você também pode fazer referência a uma combinação por seu índice (em ordem lexicográfica). Percebendo que o índice deve sofrer alguma alteração da direita para a esquerda com base no índice, podemos construir algo que deve recuperar uma combinação.
Então, temos um conjunto {1,2,3,4,5,6} ... e queremos três elementos. Digamos que {1,2,3} podemos dizer que a diferença entre os elementos é uma e em ordem e mínima. {1,2,4} tem uma alteração e é lexicograficamente o número 2. Portanto, o número de 'alterações' no último local é responsável por uma alteração na ordem lexicográfica. O segundo lugar, com uma alteração {1,3,4}, tem uma alteração, mas é responsável por mais alterações, pois fica em segundo lugar (proporcional ao número de elementos no conjunto original).
O método que descrevi é uma desconstrução, ao que parece, do conjunto para o índice, precisamos fazer o inverso - o que é muito mais complicado. É assim que a Buckles resolve o problema. Escrevi C para computá-los , com pequenas alterações - usei o índice dos conjuntos em vez de um intervalo numérico para representar o conjunto, por isso estamos sempre trabalhando de 0 ... n. Nota:
Índice de combinações em ordem lexicográfica (McCaffrey)
Existe outra maneira : seu conceito é mais fácil de entender e programar, mas sem as otimizações do Buckles. Felizmente, também não produz combinações duplicadas:
O conjunto que maximiza , onde .
Para um exemplo:
27 = C(6,4) + C(5,3) + C(2,2) + C(1,1)
. Portanto, a 27ª combinação lexicográfica de quatro coisas é: {1,2,5,6}, esses são os índices de qualquer conjunto que você queira examinar. O exemplo abaixo (OCaml) requerchoose
função, deixada para o leitor:Um iterador de combinações pequenas e simples
Os dois algoritmos a seguir são fornecidos para fins didáticos. Eles implementam um iterador e combinações gerais de pastas (mais gerais). Eles são o mais rápido possível, tendo a complexidade O ( n C k ). O consumo de memória é limitado por
k
.Começaremos com o iterador, que chamará uma função fornecida pelo usuário para cada combinação
Uma versão mais geral chamará a função fornecida pelo usuário juntamente com a variável state, iniciando no estado inicial. Como precisamos passar o estado entre estados diferentes, não usaremos o loop for, mas usar recursão,
fonte
Em c #:
Uso:
Resultado:
fonte
var result = new[] { 1, 2, 3, 4, 5 }.Combinations(3);
Solução Java curta:
O resultado será
fonte
Posso apresentar minha solução Python recursiva para esse problema?
Exemplo de uso:
Eu gosto pela sua simplicidade.
fonte
len(tuple(itertools.combinations('abcdefgh',3)))
conseguirá a mesma coisa em Python com menos código.for i in xrange(len(elements) - length + 1):
? Não importa em python, pois a saída do índice de fatia é tratada normalmente, mas é o algoritmo correto.Digamos que sua matriz de letras fique assim: "ABCDEFGH". Você tem três índices (i, j, k) indicando quais letras você usará para a palavra atual. Você começa com:
Primeiro você varia k, então a próxima etapa é assim:
Se você chegou ao fim, continua e varia j e depois k novamente.
Quando você alcança G, você também começa a variar i.
Escrito em código isso parece algo assim
fonte
O seguinte algoritmo recursivo seleciona todas as combinações de elementos k de um conjunto ordenado:
i
da sua combinaçãoi
com cada uma das combinações dek-1
elementos escolhidos recursivamente do conjunto de elementos maior quei
.Repita o procedimento acima para cada um
i
no conjunto.É essencial que você escolha o restante dos elementos como maior que
i
, para evitar repetições. Dessa forma, [3,5] será escolhido apenas uma vez, como [3] combinado com [5], em vez de duas vezes (a condição elimina [5] + [3]). Sem essa condição, você obtém variações em vez de combinações.fonte
Em C ++, a seguinte rotina produzirá todas as combinações de distância de comprimento (primeiro, k) entre o intervalo [primeiro, último):
Pode ser usado assim:
Isso imprimirá o seguinte:
fonte
being
ebegin
pors.begin()
eend
coms.end()
. O código segue de perto onext_permutation
algoritmo do STL , descrito aqui em mais detalhes.Achei este tópico útil e pensei em adicionar uma solução Javascript que você possa acessar no Firebug. Dependendo do seu mecanismo JS, pode demorar um pouco se a sequência inicial for grande.
A saída deve ser a seguinte:
fonte
fonte
Pequeno exemplo em Python:
Para explicação, o método recursivo é descrito com o seguinte exemplo:
Exemplo: ABCDE
Todas as combinações de 3 seriam:
fonte
Algoritmo recursivo simples em Haskell
Primeiro, definimos o caso especial, ou seja, a seleção de zero elementos. Produz um único resultado, que é uma lista vazia (ou seja, uma lista que contém uma lista vazia).
Para n> 0,
x
percorre todos os elementos da lista exs
todos os elementos apósx
.rest
escolhen - 1
elementos doxs
uso de uma chamada recursiva paracombinations
. O resultado final da função é uma lista em que cada elemento estáx : rest
(ou seja, uma lista que temx
como cabeçalho erest
como cauda) para cada valor diferente dex
erest
.E, é claro, como Haskell é preguiçoso, a lista é gerada gradualmente conforme necessário, para que você possa avaliar parcialmente combinações exponencialmente grandes.
fonte
E aqui vem o avô COBOL, a linguagem muito difamada.
Vamos assumir uma matriz de 34 elementos de 8 bytes cada (seleção puramente arbitrária). A idéia é enumerar todas as combinações possíveis de 4 elementos e carregá-las em uma matriz.
Utilizamos 4 índices, um para cada posição no grupo de 4
A matriz é processada assim:
Nós variamos idx4 de 4 até o final. Para cada idx4, obtemos uma combinação única de grupos de quatro. Quando o idx4 chega ao final da matriz, incrementamos o idx3 em 1 e configuramos o idx4 como idx3 + 1. Então rodamos o idx4 até o fim novamente. Prosseguimos dessa maneira, aumentando idx3, idx2 e idx1, respectivamente, até que a posição de idx1 seja menor que 4 do final da matriz. Isso termina o algoritmo.
Primeiras iterações:
Um exemplo de COBOL:
fonte
Aqui está uma implementação elegante e genérica no Scala, conforme descrito em 99 Scala Problems .
fonte
Se você pode usar a sintaxe SQL - por exemplo, se estiver usando o LINQ para acessar campos de uma estrutura ou matriz ou acessando diretamente um banco de dados que possui uma tabela chamada "Alfabeto" com apenas um campo de caracteres "Carta", você pode adaptar-se a seguir código:
Isso retornará todas as combinações de 3 letras, não obstante quantas letras você tenha na tabela "Alfabeto" (pode ser 3, 8, 10, 27, etc.).
Se o que você deseja são todas permutações, em vez de combinações (ou seja, você deseja que "ACB" e "ABC" sejam contados como diferentes, em vez de aparecer apenas uma vez), exclua a última linha (a AND) e está pronta.
Pós-edição: Depois de reler a pergunta, percebo que o necessário é o algoritmo geral , não apenas um específico para o caso de seleção de 3 itens. A resposta de Adam Hughes é a completa, infelizmente ainda não posso votar. Essa resposta é simples, mas funciona apenas para quando você deseja exatamente 3 itens.
fonte
Outra versão C # com geração lenta dos índices de combinação. Esta versão mantém uma única matriz de índices para definir um mapeamento entre a lista de todos os valores e os valores da combinação atual, ou seja, constantemente usa O (k) espaço adicional durante todo o tempo de execução. O código gera combinações individuais, incluindo a primeira, em O (k) .
Código do teste:
Resultado:
fonte
c b a
que não contém .https://gist.github.com/3118596
Existe uma implementação para JavaScript. Possui funções para obter combinações k e todas as combinações de uma matriz de qualquer objeto. Exemplos:
fonte
Aqui você tem uma versão avaliada preguiçosa desse algoritmo codificado em C #:
E peça de teste:
Espero que isso ajude você!
fonte
Eu tinha um algoritmo de permutação que usei para o projeto euler, em python:
E se
você deve ter todas as combinações necessárias sem repetição, precisa?
É um gerador, então você o usa em algo assim:
fonte
fonte
Versão Clojure:
fonte
Digamos que sua matriz de letras fique assim: "ABCDEFGH". Você tem três índices (i, j, k) indicando quais letras você usará para a palavra atual. Você começa com:
Primeiro você varia k, então a próxima etapa é assim:
Se você chegou ao fim, continua e varia j e depois k novamente.
Quando você alcança G, você também começa a variar i.
Com base em https://stackoverflow.com/a/127898/2628125 , mas mais abstrato, para qualquer tamanho de ponteiro.
fonte
Tudo dito e feito aqui vem o código O'caml para isso. Algoritmo é evidente a partir do código ..
fonte
Aqui está um método que fornece todas as combinações de tamanho especificado a partir de uma sequência de comprimento aleatório. Semelhante à solução dos quinmars, mas funciona para entradas variadas e k.
O código pode ser alterado para contornar, ou seja, 'dab' da entrada 'abcd' wk = 3.
Saída para "abcde":
fonte
código python curto, gerando posições de índice
fonte
Criei uma solução no SQL Server 2005 para isso e publiquei no meu site: http://www.jessemclain.com/downloads/code/sql/fn_GetMChooseNCombos.sql.htm
Aqui está um exemplo para mostrar o uso:
resultados:
fonte
Aqui está minha proposição em C ++
Tentei impor o mínimo de restrição possível ao tipo de iterador, portanto esta solução assume apenas o iterador para a frente e pode ser um const_iterator. Isso deve funcionar com qualquer contêiner padrão. Nos casos em que os argumentos não fazem sentido, lança std :: invalid_argumnent
fonte
Aqui está um código que escrevi recentemente em Java, que calcula e retorna toda a combinação de elementos "num" de elementos "outOf".
fonte
Uma solução Javascript concisa:
fonte
Algoritmo:
Em c #:
Por que isso funciona?
Há uma bijeção entre os subconjuntos de um conjunto de elementos n e seqüências de n bits.
Isso significa que podemos descobrir quantos subconjuntos existem contando seqüências.
por exemplo, o conjunto de quatro elementos abaixo pode ser representado por {0,1} X {0, 1} X {0, 1} X {0, 1} (ou 2 ^ 4) diferentes seqüências.
Então - tudo o que precisamos fazer é contar de 1 a 2 ^ n para encontrar todas as combinações. (Ignoramos o conjunto vazio.) Em seguida, traduza os dígitos para sua representação binária. Em seguida, substitua os elementos do seu conjunto por bits 'on'.
Se você deseja apenas resultados do elemento k, imprima apenas quando k bits estiverem 'ativados'.
(Se você deseja todos os subconjuntos, em vez de k length, remova a parte cnt / kElement.)
(Para comprovação, consulte os cursos gratuitos do MIT, Matemática para Ciência da Computação, Lehman et al, seção 11.2.2. Https://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-042j-mathematics- for-computer-science-fall-2010 / leituras / )
fonte
Eu escrevi uma classe para lidar com funções comuns para trabalhar com o coeficiente binomial, que é o tipo de problema em que seu problema se enquadra. Ele executa as seguintes tarefas:
Produz todos os índices K em um bom formato para qualquer N, escolha K em um arquivo. Os índices K podem ser substituídos por seqüências ou letras mais descritivas. Esse método torna a solução desse tipo de problema bastante trivial.
Converte os índices K no índice adequado de uma entrada na tabela de coeficientes binomiais classificados. Essa técnica é muito mais rápida que as técnicas publicadas mais antigas que dependem da iteração. Isso é feito usando uma propriedade matemática inerente ao Triângulo de Pascal. Meu trabalho fala sobre isso. Acredito que sou o primeiro a descobrir e publicar essa técnica, mas posso estar errado.
Converte o índice em uma tabela de coeficiente binomial classificado nos índices K correspondentes.
Usa o método Mark Dominus para calcular o coeficiente binomial, que tem muito menos probabilidade de transbordar e funciona com números maiores.
A classe é escrita no .NET C # e fornece uma maneira de gerenciar os objetos relacionados ao problema (se houver) usando uma lista genérica. O construtor dessa classe usa um valor bool chamado InitTable que, quando true, criará uma lista genérica para armazenar os objetos a serem gerenciados. Se esse valor for falso, ele não criará a tabela. A tabela não precisa ser criada para executar os 4 métodos acima. Métodos de assessor são fornecidos para acessar a tabela.
Existe uma classe de teste associada que mostra como usar a classe e seus métodos. Foi extensivamente testado com 2 casos e não há bugs conhecidos.
Para ler sobre esta classe e fazer o download do código, consulte Tablizing The Binomial Coeffieicent .
Não deve ser difícil converter essa classe para C ++.
fonte