Acabei de bombardear uma entrevista e fiz praticamente zero progresso em minha pergunta. Alguém pode me informar como fazer isso? Tentei pesquisar online, mas não consegui encontrar nada:
Dado um número, encontre o próximo número mais alto que tenha exatamente o mesmo conjunto de dígitos que o número original. Por exemplo: dado 38276, retorne 38627
Eu queria começar encontrando o índice do primeiro dígito (da direita) que fosse menor que o dígito um. Depois, eu rodava os últimos dígitos do subconjunto, de modo que este fosse o próximo número maior composto pelos mesmos dígitos, mas fiquei preso.
O entrevistador também sugeriu tentar trocar os dígitos um de cada vez, mas não consegui descobrir o algoritmo e fiquei olhando a tela por 20 a 30 minutos. Escusado será dizer que acho que vou ter que continuar a procura de emprego.
editar: por que vale a pena, fui convidado para a próxima rodada de entrevistas
next_permutation
;-)Respostas:
Você pode fazer isso
O(n)
(onden
está o número de dígitos) assim:Começando pela direita, você encontra o primeiro par de dígitos, de modo que o dígito esquerdo seja menor que o dígito direito. Vamos nos referir ao dígito esquerdo por "dígito-x". Encontre o menor número maior que o dígito x à direita do dígito x e coloque-o imediatamente à esquerda do dígito x. Por fim, classifique os dígitos restantes em ordem crescente - como eles já estavam em ordem decrescente , tudo o que você precisa fazer é revertê-los (exceto o dígito x, que pode ser colocado no local correto em
O(n)
) .Um exemplo tornará isso mais claro:
Prova de correção:
Vamos usar letras maiúsculas para definir cadeias de dígitos e letras minúsculas para dígitos. A sintaxe
AB
significa "a concatenação de stringsA
eB
" .<
é uma ordem lexicográfica, que é igual à ordem inteira quando as cadeias de dígitos têm o mesmo comprimento.Nosso número original N é do formato
AxB
, ondex
é um único dígito eB
é classificado em ordem decrescente.O número encontrado por nosso algoritmo é
AyC
, ondey ∈ B
está o menor dígito> x
(ele deve existir devido à maneira comox
foi escolhido, veja acima) eC
é classificado em ordem crescente.Suponha que exista um número (usando os mesmos dígitos)
N'
tal queAxB < N' < AyC
.N'
deve começar com,A
ou então não poderia ficar entre eles, para que possamos escrevê-lo no formulárioAzD
. Agora, nossa desigualdade éAxB < AzD < AyC
equivalente axB < zD < yC
onde todas as três cadeias de dígitos contêm os mesmos dígitos.Para que isso seja verdade, devemos ter
x <= z <= y
. Dado quey
é o dígito mais pequeno> x
,z
não pode estar entre eles, portanto,z = x
ouz = y
. Digaz = x
. Então nossa desigualdade éxB < xD < yC
, o que significaB < D
onde ambosB
eD
têm os mesmos dígitos. No entanto, B é descendente ordenada, por isso não é nenhuma corda com esses dígitos maiores do que ele. Assim, não podemos terB < D
. Seguindo os mesmos passos, vemos quez = y
, se não podemos terD < C
.Portanto,
N'
não pode existir, o que significa que nosso algoritmo encontra corretamente o próximo maior número.fonte
9 832
depois classificaria tudo à direita de 9:9238
Um problema quase idêntico apareceu como um problema do Code Jam e tem uma solução aqui:
http://code.google.com/codejam/contest/dashboard?c=186264#s=a&a=1
Aqui está um resumo do método usando um exemplo:
A. Divida a sequência de dígitos em dois, para que a parte direita seja o maior possível, permanecendo em ordem decrescente:
(Se o número inteiro estiver em ordem decrescente, não será possível criar um número maior sem adicionar dígitos.)
B.1 Selecione o último dígito da primeira sequência:
B.2 Encontre o dígito menor na segunda sequência que é maior que ele:
B.3 Troque-os:
C. Classifique a segunda sequência em ordem crescente:
D. Feito!
fonte
Aqui está uma solução compacta (mas parcialmente bruta) em Python
Em C ++, você poderia fazer permutações como esta: https://stackoverflow.com/a/9243091/1149664 (É o mesmo algoritmo que o do itertools)
Aqui está uma implementação da resposta principal descrita por Weeble e BlueRaja (outras respostas). Duvido que haja algo melhor.
fonte
type 'map' has no len()
. Eu mudaria a segunda linha paraiis=list(map(int,str(ii)))
. E alguém poderia explicar aif i == 0: return ii
linha, por favor? Por que funcionaria com entradas como 111 ou 531? Obrigado.i == len(iis)
.No mínimo, aqui estão alguns exemplos de soluções baseadas em String de força bruta, que você deveria ter conseguido pensar desde o início:
a lista de dígitos
38276
classificados é23678
a lista de dígitos
38627
classificados é23678
incremento da força bruta, classifique e compare
Ao longo da força bruta, as soluções seriam convertidas em String e força bruta, todos os números possíveis usando esses dígitos.
Crie entradas a partir de todas elas, coloque-as em uma lista e classifique-as, obtenha a próxima entrada após a entrada de destino.
Se você gastou 30 minutos nisso e não apresentou pelo menos uma abordagem de força bruta, eu também não o contrataria.
No mundo dos negócios, uma solução deselegante, lenta e desajeitada, mas que realiza o trabalho, é sempre mais valiosa do que nenhuma solução, fato que descreve praticamente todos os softwares comerciais deselegantes, lentos e desajeitados.
fonte
fonte
Sua ideia
é muito bom, na verdade. Você apenas precisa considerar não apenas o último dígito, mas todos os dígitos com menos significado do que o atualmente considerado. Como antes disso, temos uma sequência monotônica de dígitos, que é o dígito mais à direita menor que seu vizinho direito. Que diz respeito
O próximo número maior com os mesmos dígitos é
O dígito encontrado é trocado pelo último dígito - o menor dos dígitos considerados - e os dígitos restantes são organizados em ordem crescente.
fonte
Tenho certeza de que seu entrevistador estava tentando empurrá-lo gentilmente para algo assim:
Não necessariamente a solução mais eficiente ou elegante, mas resolve o exemplo fornecido em dois ciclos e troca os dígitos um de cada vez, como ele sugeriu.
fonte
Pegue um número e divida-o em dígitos. Portanto, se tivermos um número de 5 dígitos, teremos 5 dígitos: abcde
Agora troque d e e compare com o número original, se for maior, você tem sua resposta.
Se não for maior, troque e e c. Agora compare e se for menor troca d e e novamente (aviso de recursão), pegue o menor.
Continue até encontrar um número maior. Com a recursão, deve funcionar com cerca de 9 linhas de esquema, ou 20 de c #.
fonte
Essa é uma pergunta muito interessante.
Aqui está a minha versão java. Demore cerca de três horas para descobrir o padrão para concluir completamente o código antes de verificar os comentários de outros colaboradores. Fico feliz em ver a minha idéia é a mesma com os outros.
O (n) solução. Sinceramente, vou falhar nesta entrevista se o tempo for de apenas 15 minutos e exigir o término completo do código no quadro branco.
Aqui estão alguns pontos interessantes para a minha solução:
Coloquei comentários detalhados no meu código e o Big O em cada etapa.
Aqui está o resultado em execução no Intellj:
fonte
Uma implementação em javascript do algoritmo do @ BlueRaja.
fonte
Uma solução (em Java) poderia ser a seguinte (tenho certeza de que os amigos podem encontrar um melhor):
Comece a trocar dígitos do final da string até obter um número maior.
Ou seja, primeiro comece a subir o dígito inferior. Em seguida, o próximo mais alto etc. até você atingir o próximo mais alto.
Depois, organize o resto. No seu exemplo, você obteria:
fonte
63872
. Por que, o que deveria ser?Se você estiver programando em C ++, poderá usar
next_permutation
:fonte
100
? :-)Eu não sabia nada sobre o algoritmo de força bruta ao responder a essa pergunta, então me aproximei de outro ângulo. Decidi pesquisar em toda a gama de soluções possíveis em que esse número poderia ser reorganizado, começando do número_ dado + 1 até o número máximo disponível (999 para um número de 3 dígitos, 9999 para 4 dígitos, etc.). Eu meio que encontrei um palíndromo com palavras, classificando os números de cada solução e comparando-o com o número classificado fornecido como parâmetro. Simplesmente retornei a primeira solução no conjunto de soluções, pois esse seria o próximo valor possível.
Aqui está o meu código no Ruby:
fonte
Código PHP
fonte
Eu só testei isso com dois números. Eles trabalharam. Como gerente de TI, durante oito anos, até me aposentar em dezembro passado, eu me preocupava com três coisas: 1) Precisão: é bom se funcionar - sempre. 2) Velocidade: deve ser aceitável pelo usuário. 3) Clareza: Provavelmente não sou tão inteligente quanto você, mas estou pagando. Certifique-se de explicar o que está fazendo, em inglês.
Omar, boa sorte daqui para frente.
fonte
Para uma boa descrição de como fazer isso, consulte " Algoritmo L " em " The Art of Programming Computer: Generating All Permutations " de Knuth (.ps.gz).
fonte
Aqui está o meu código, é uma versão modificada deste exemplo
Biblioteca:
Teste:
fonte
Adicione 9 ao número de n dígitos fornecido. Depois verifique se está dentro do limite (o primeiro (n + 1) número do dígito). Se for, verifique se os dígitos no novo número são iguais aos dígitos no número original. Repita adicionando 9 até que ambas as condições sejam verdadeiras. Pare o algo quando o número ultrapassar o limite.
Não pude apresentar um caso de teste contraditório para esse método.
fonte
Apenas outra solução usando python:
Resultado:
fonte
fonte
Abaixo está o código para gerar todas as permutações de um número .. embora seja necessário converter esse número inteiro em string usando String.valueOf (número inteiro) primeiro.
fonte
fonte
Mais uma implementação Java, executável fora da caixa e concluída com testes. Esta solução é O (n) espaço e tempo usando boa e velha programação dinâmica.
Se alguém quiser bruteforce, existem 2 tipos de bruteforce:
Permita todas as coisas e escolha min mais alto: O (n!)
Semelhante a esta implementação, mas em vez de DP, a execução forçada da etapa de preenchimento do mapa indexToIndexOfNextSmallerLeft será executada em O (n ^ 2).
fonte
Precisamos encontrar o bit mais à direita 0 seguido de 1 e virar esse bit mais à direita para 1.
por exemplo, digamos que nossa entrada seja 487, que é 111100111 em binário.
nós giramos o mais à direita 0 que tem 1 a seguir
então temos 111101111
mas agora temos 1 extra e menos 0, então reduzimos o número de 1 à direita do flip bit em 1 e aumentamos o número de 0 bits em 1, produzindo
111101011 - binário 491
fonte
fonte
Aqui está a implementação Java
Aqui estão os testes de unidade
fonte
Eu sei que essa é uma pergunta muito antiga, mas ainda não encontrei um código fácil em c #. Isso pode ajudar os caras que estão participando de entrevistas.
fonte
Implementação muito simples usando Javascript, próximo número mais alto com os mesmos dígitos
Como existem muitos comentários, é melhor copiá-lo para o seu editor de texto. Obrigado!
fonte
Há muitas boas respostas, mas não encontrei uma implementação decente de Java. Aqui estão meus dois centavos:
fonte
fonte