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

226

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

bhan
fonte
15
sem pensar muito, uma partida pelo menos seria a força bruta, calcule todas as permutações dos dígitos e pegue o número mínimo maior que o número de entrada.
BrokenGlass
13
em C ++ você pode apenas usar next_permutation;-)
thedayturns
9
Para sua informação, veja como eu o resolvi em cerca de 15 minutos enquanto mal pensava no problema: passei 5 minutos escrevendo um algoritmo de força bruta que apenas criou todas as permutações possíveis de um conjunto de dígitos, classificou-os e os exibiu. Passei 5 minutos examinando esses dados até que um padrão emergisse da lista (a solução O (n) aceita aqui ficou clara após pouco tempo de pesquisa), depois passei 5 minutos codificando o algoritmo O (n).
Ben Lee
1
Em geral, essa não é uma maneira ruim de apresentar algoritmos para resolver esse tipo de problema quando você está preso - use força bruta em alguma amostra pequena para criar muitos dados que você poderá usar para ver padrões mais facilmente.
Ben Lee
19
Eu também gostaria de salientar que, se você realmente não consegue descobrir uma maneira eficiente de fazer isso, não fazer nada é uma maneira de falhar na entrevista (e no mundo dos negócios, é uma maneira de perder o prazo do produto) . Quando você ficou paralisado, em vez de desistir, deveria ter forçado a bruta e colocar um comentário no topo "TODO: refatorar o desempenho" ou algo assim. Se eu estivesse entrevistando e alguém fizesse isso, não falharia necessariamente com eles. Pelo menos eles criaram algo que funcionou E reconheceram que algo melhor estava por aí, mesmo que não o encontrassem.
21412 Ben Lee

Respostas:

272

Você pode fazer isso O(n)(onde nestá 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:

123456784987654321
comece com um número

123456784 987654321
         ^ o primeiro lugar da direita, onde o dígito esquerdo é menor que o direito  
         O dígito "x" é 4

123456784 987654321
              ^ encontre o menor dígito maior que 4 à direita

123456785 4 98764321
        ^ coloque-o à esquerda de 4

123456785 4 12346789
123456785123446789
         ^ classifique os dígitos à direita de 5. Como todos eles, exceto 
         os '4' já estavam em ordem decrescente, tudo o que precisamos fazer é 
         inverter a ordem e encontrar o local correto para o '4'

Prova de correção:

Vamos usar letras maiúsculas para definir cadeias de dígitos e letras minúsculas para dígitos. A sintaxe ABsignifica "a concatenação de strings Ae B" . <é 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, onde xé um único dígito e Bé classificado em ordem decrescente.
O número encontrado por nosso algoritmo é AyC, onde y ∈ Bestá o menor dígito > x (ele deve existir devido à maneira como xfoi escolhido, veja acima) e Cé classificado em ordem crescente.

Suponha que exista um número (usando os mesmos dígitos) N'tal que AxB < N' < AyC. N'deve começar com, Aou então não poderia ficar entre eles, para que possamos escrevê-lo no formulário AzD. Agora, nossa desigualdade é AxB < AzD < AyCequivalente a xB < zD < yConde 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 que yé o dígito mais pequeno > x, znão pode estar entre eles, portanto, z = xou z = y. Diga z = x. Então nossa desigualdade é xB < xD < yC, o que significa B < Donde ambos Be Dtê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 ter B < D. Seguindo os mesmos passos, vemos que z = y, se não podemos ter D < C.

Portanto, N'não pode existir, o que significa que nosso algoritmo encontra corretamente o próximo maior número.

BlueRaja - Danny Pflughoeft
fonte
7
boa solução! tenho uma pergunta. diga "o menor dígito maior que x" é y. podemos apenas trocar xey, então inverter x.index + 1 -> end?
21712 Kent
8
O que acontece com o número 99999?
Sterex
19
@ Sterex, não é apenas 99999; qualquer número cujos dígitos já estejam totalmente classificados em ordem decrescente é o máximo (portanto, 98765 também não tem solução, por exemplo). Isso é fácil de detectar de forma programática porque a etapa 1 do algoritmo falhará (não há um par de dígitos consecutivos, de modo que "o dígito esquerdo seja menor que o dígito direito").
21412 Ben Lee
3
@TMN: 9 é maior que 8, então você moveria 9 para a esquerda de 8: 9 832depois classificaria tudo à direita de 9:9238
BlueRaja - Danny Pflughoeft
4
@Kent para a sua solução de trabalho que você terá que mudar encontrar o menor dígito maior que 4 para a direita para encontrar o menor dígito maior que 4 a partir da direita . Caso contrário, por exemplo, 1234567849876 55 4321 resultará em 1234567851234 54 6789 (em vez de 1234567851234 45 6789). Um nitpick :-) #
osundblad
94

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:

34722641

A. Divida a sequência de dígitos em dois, para que a parte direita seja o maior possível, permanecendo em ordem decrescente:

34722 641

(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:

3472(2) 641

B.2 Encontre o dígito menor na segunda sequência que é maior que ele:

3472(2) 6(4)1

B.3 Troque-os:

3472(2) 6(4)1
->
3472(4) 6(2)1
->
34724 621

C. Classifique a segunda sequência em ordem crescente:

34724 126

D. Feito!

34724126
Weeble
fonte
1
Erro de digitação lá: Eu acho que "-> 34721 621" deveria ser "-> 34724 621"?
bjnord
1
@bjnord Boa captura. Fixo. Não tenho certeza de como eu consegui isso - estava correto nas linhas subseqüentes.
Weeble
+1 Melhor resposta aqui. Intuitivo e rápido. (que também é a aquela que eu pensei quando eu trabalhava isso no papel;))
Muhd
1
@ Neel - Na etapa C, os dígitos que queremos classificar estão em ordem decrescente, exceto o dígito que trocamos na etapa B. Para classificá-los, na verdade precisamos revertê-los e colocar o dígito trocado na posição correta. É isso que o BlueRaja descreve.
Weeble
1
@Dhavaldave Qual é o problema? Na etapa A, você obtém "12" e "3". Na etapa B, você obtém "13" e "2". Na etapa C, nada muda. Na etapa D, você obtém "132". O único caso em que você não recebe resposta é quando o número já é o máximo possível, por exemplo, "321". Nesse caso, a etapa A fornece "" e "321" e você não pode prosseguir com uma sequência vazia para o lado esquerdo da divisão.
precisa
14

Aqui está uma solução compacta (mas parcialmente bruta) em Python

def findnext(ii): return min(v for v in (int("".join(x)) for x in
    itertools.permutations(str(ii))) if v>ii)

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.

def findnext(ii):
    iis=list(map(int,str(ii)))
    for i in reversed(range(len(iis))):
        if i == 0: return ii
        if iis[i] > iis[i-1] :
            break        
    left,right=iis[:i],iis[i:]
    for k in reversed(range(len(right))):
        if right[k]>left[-1]:
           right[k],left[-1]=left[-1],right[k]
           break
    return int("".join(map(str,(left+sorted(right)))))
Johan Lundberg
fonte
Alguma chance de alguém atualizar isso, por favor? Não parece funcionar no Python 3, como mostra type 'map' has no len(). Eu mudaria a segunda linha para iis=list(map(int,str(ii))). E alguém poderia explicar a if i == 0: return iilinha, por favor? Por que funcionaria com entradas como 111 ou 531? Obrigado.
Bowen Liu
Corrigi-o agora para python 3 adicionando ´list () a iis = ... ´. Os casos 111 e 531 não têm solução, mas minha implementação retorna 111 e 531 para eles. Você pode mudar isso para uma exceção do que achar melhor, alterando a linha i == 0.
Johan Lundberg
Obrigado. Na verdade, eu faço um loop na outra direção, então fiquei confuso com o i == 0, enquanto na minha situação será i == len(iis).
18118 Bowen Liu #:
8

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 38276classificados é23678

a lista de dígitos 38627classificados é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
1
Bem, meu primeiro comentário fora do bastão foi: "Eu poderia forçá-lo, mas ...". Se não há realmente uma solução algorítmica, estou um pouco desapontado
bhan
4
Se eu fosse o entrevistador, não ficaria tão feliz com uma abordagem de força bruta.
Ahmad Y. Saleh
@ Benjamin Benjamin, existe uma solução algorítmica. Continue trocando os dígitos a partir da direita, até encontrar o resultado. Não há necessidade de calcular todos os permutatnios antes.
dantuch
7
Certamente, existem soluções muito melhores do que a força bruta, por exemplo: ardendertat.com/2012/01/02/… #
BrokenGlass
@BrokenGlass Definitivamente, uma solução muito melhor. Eu estava pensando nisso e você postou o algoritmo.
Onit
5
function foo(num){
 sortOld = num.toString().split("").sort().join('');
 do{
    num++;
   sortNew = num.toString().split("").sort().join('');
 }while(sortNew!==sortOld);
 return num;
}
Ashikodi
fonte
Eu vim com esta solução. Por favor, se você tiver alguma dúvida, pergunte.
Ashikodi 01/06/2015
4

Sua ideia

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.

é 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

1234675
    ^

O próximo número maior com os mesmos dígitos é

1234756

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.

Daniel Fischer
fonte
4

Tenho certeza de que seu entrevistador estava tentando empurrá-lo gentilmente para algo assim:

local number = 564321;

function split(str)
    local t = {};
    for i = 1, string.len(str) do
        table.insert(t, str.sub(str,i,i));
    end
    return t;
end

local res = number;
local i = 1;
while number >= res do
    local t = split(tostring(res));
    if i == 1 then
        i = #t;
    end
    t[i], t[i-1] = t[i-1], t[i];
    i = i - 1;
    res = tonumber(table.concat(t));
end

print(res);

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.

Lex R
fonte
2

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 #.

Roland
fonte
2

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:

  • Evite qualquer classificação.
  • Evite completamente a operação das cordas
  • Atinja a complexidade do espaço O (logN)

Coloquei comentários detalhados no meu código e o Big O em cada etapa.

  public int findNextBiggestNumber(int input  )   {
    //take 1358642 as input for example.
    //Step 1: split the whole number to a list for individual digital   1358642->[2,4,6,8,5,3,1]
    // this step is O(n)
    int digitalLevel=input;

    List<Integer> orgNumbersList=new ArrayList<Integer>()   ;

    do {
        Integer nInt = new Integer(digitalLevel % 10);
        orgNumbersList.add(nInt);

        digitalLevel=(int) (digitalLevel/10  )  ;


    } while( digitalLevel >0)    ;
    int len= orgNumbersList.size();
    int [] orgNumbers=new int[len]  ;
    for(int i=0;i<len;i++){
        orgNumbers[i ]  =  orgNumbersList.get(i).intValue();
    }
    //step 2 find the first digital less than the digital right to it
    // this step is O(n)


    int firstLessPointer=1;
    while(firstLessPointer<len&&(orgNumbers[firstLessPointer]>orgNumbers[ firstLessPointer-1 ])){
        firstLessPointer++;
    }
     if(firstLessPointer==len-1&&orgNumbers[len-1]>=orgNumbers[len-2]){
         //all number is in sorted order like 4321, no answer for it, return original
         return input;
     }

    //when step 2 step finished, firstLessPointer  pointing to number 5

     //step 3 fristLessPointer found, need to find  to  first number less than it  from low digital in the number
    //This step is O(n)
    int justBiggerPointer=  0 ;

    while(justBiggerPointer<firstLessPointer&& orgNumbers[justBiggerPointer]<orgNumbers[firstLessPointer]){
        justBiggerPointer++;
    }
    //when step 3 finished, justBiggerPointer  pointing to 6

    //step 4 swap the elements  of justBiggerPointer and firstLessPointer .
    // This  is O(1) operation   for swap

   int tmp=  orgNumbers[firstLessPointer] ;

    orgNumbers[firstLessPointer]=  orgNumbers[justBiggerPointer]  ;
     orgNumbers[justBiggerPointer]=tmp ;


     // when step 4 finished, the list looks like        [2,4,5,8,6,3,1]    the digital in the list before
     // firstLessPointer is already sorted in our previous operation
     // we can return result from this list  but  in a differrent way
    int result=0;
    int i=0;
    int lowPointer=firstLessPointer;
    //the following pick number from list from  the position just before firstLessPointer, here is 8 -> 5 -> 4 -> 2
    //This Operation is O(n)
    while(lowPointer>0)        {
        result+= orgNumbers[--lowPointer]* Math.pow(10,i);
        i++;
    }
    //the following pick number from list   from position firstLessPointer
    //This Operation is O(n)
    while(firstLessPointer<len)        {
        result+= orgNumbers[firstLessPointer++ ]* Math.pow(10,i);
        i++;
    }
     return  result;

}

Aqui está o resultado em execução no Intellj:

959879532-->959892357
1358642-->1362458
1234567-->1234576
77654321-->77654321
38276-->38627
47-->74
Boveyking
fonte
no caso 123, qual será a resposta? Praticamente código de retorno vai não irá gerar a saída, enquanto que shold vir 132
Dhaval dave
2

Uma implementação em javascript do algoritmo do @ BlueRaja.

var Bar = function(num){ 
  num = num.toString();
  var max = 0;
  for(var i=num.length-2; i>0; i--){
    var numArray = num.substr(i).split("");
    max = Math.max.apply(Math,numArray);
    if(numArray[0]<max){
        numArray.sort(function(a,b){return a-b;});
        numArray.splice(-1);
        numArray = numArray.join("");
        return Number(num.substr(0,i)+max+numArray);
    }
  }
  return -1;
};
neddinn
fonte
1

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:

38276 --> 38267 (smaller) --> 38627 Found it    
    ^        ^                  ^        

 public static int nextDigit(int number){
    String num = String.valueOf(number);        
    int stop = 0;       
    char [] chars = null;
    outer:
        for(int i = num.length() - 1; i > 0; i--){          
            chars = num.toCharArray();
            for(int j = i; j > 0; j--){
                char temp = chars[j];
                chars[j] = chars[j - 1];
                chars[j - 1] = temp;
                if(Integer.valueOf(new String(chars)) > number){
                    stop = j;                   
                    break outer;                                
                }               
            }               
        }

    Arrays.sort(chars, stop, chars.length); 
    return Integer.valueOf(new String(chars));
}
Cratylus
fonte
@yi_H: A saída é 63872. Por que, o que deveria ser?
Cratylus
bem .. próximo número mais alto? :) esse era o requisito, não era?
Karoly Horvath
@BlueRaja - Danny Pflughoeft: Obrigado por sua ajuda. Alterei o código da seguinte forma: Mova o mínimo dígito para frente (o que sempre gera um número maior) e classifique o resto #
Cratylus
1

Se você estiver programando em C ++, poderá usar next_permutation:

#include <algorithm>
#include <string>
#include <iostream>

int main(int argc, char **argv) {
  using namespace std; 
   string x;
   while (cin >> x) {
    cout << x << " -> ";
    next_permutation(x.begin(),x.end());
    cout << x << "\n";
  }
  return 0;
}
nibot
fonte
O que acontece se eu inserir 100? :-)
jweyrich 26/10
1

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:

def PermutationStep(num)

    a = []
    (num.to_s.length).times { a.push("9") }
    max_num = a.join('').to_i
    verify = num.to_s.split('').sort
    matches = ((num+1)..max_num).select {|n| n.to_s.split('').sort == verify }

    if matches.length < 1
      return -1
    else
      matches[0]
    end
end
Jeremiah McCurdy
fonte
qual é a complexidade temporal desta solução?
Nitish Upreti
@ Myth17 Não tenho certeza, pois nunca testei. Porém, se você quiser descobrir isso, confira este post: stackoverflow.com/questions/9958299/…
Jeremiah McCurdy
1

Código PHP

function NextHigherNumber($num1){
$num = strval($num1);
$max = 0;
for($i=(strlen($num)-2); $i>=0; $i--){
    $numArrayRaw = substr($num, $i);
    $numArray = str_split($numArrayRaw);
    $max = max($numArray);
    if ($numArray[0] < $max){
        sort( $numArray, SORT_NUMERIC );
        array_pop($numArray);
        $numarrstr = implode("",$numArray);
        $rt = substr($num,0,$i) . $max . $numarrstr;
        return $rt;
    }
}
return "-1";
}
echo NextHigherNumber(123);
Bilal Kabeer Butt
fonte
0

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.

Sub Main()

Dim Base(0 To 9) As Long
Dim Test(0 To 9) As Long

Dim i As Long
Dim j As Long
Dim k As Long
Dim ctr As Long

Const x As Long = 776914648
Dim y As Long
Dim z As Long

Dim flag As Boolean

' Store the digit count for the original number in the Base vector.
    For i = 0 To 9
        ctr = 0
        For j = 1 To Len(CStr(x))
            If Mid$(CStr(x), j, 1) = i Then ctr = ctr + 1
        Next j
        Base(i) = ctr
    Next i

' Start comparing from the next highest number.
    y = x + 1
    Do

' Store the digit count for the each new number in the Test vector.
        flag = False
        For i = 0 To 9
            ctr = 0
            For j = 1 To Len(CStr(y))
                If Mid$(CStr(y), j, 1) = i Then ctr = ctr + 1
            Next j
            Test(i) = ctr
        Next i

' Compare the digit counts.
        For k = 0 To 9
            If Test(k) <> Base(k) Then flag = True
        Next k

' If no match, INC and repeat.
        If flag = True Then
            y = y + 1
            Erase Test()
        Else
            z = y ' Match.
        End If

    Loop Until z > 0

    MsgBox (z), , "Solution"

End Sub
David Healy
fonte
0

Aqui está o meu código, é uma versão modificada deste exemplo

Biblioteca:

class NumPermExample
{
    // print N! permutation of the characters of the string s (in order)
    public  static void perm1(String s, ArrayList<String> perm)
    {
        perm1("", s);
    }

    private static void perm1(String prefix, String s, ArrayList<String> perm)
    {
        int N = s.length();
        if (N == 0)
        {
            System.out.println(prefix);
            perm.add(prefix);
        }
        else
        {
            for (int i = 0; i < N; i++)
                perm1(prefix + s.charAt(i), s.substring(0, i)
                    + s.substring(i+1, N));
        }

    }

    // print N! permutation of the elements of array a (not in order)
    public static void perm2(String s, ArrayList<String> perm)
    {
       int N = s.length();
       char[] a = new char[N];
       for (int i = 0; i < N; i++)
           a[i] = s.charAt(i);
       perm2(a, N);
    }

    private static void perm2(char[] a, int n, ArrayList<String> perm)
    {
        if (n == 1)
        {
            System.out.println(a);
            perm.add(new String(a));
            return;
        }

        for (int i = 0; i < n; i++)
        {
            swap(a, i, n-1);
            perm2(a, n-1);
            swap(a, i, n-1);
        }
    }  

    // swap the characters at indices i and j
    private static void swap(char[] a, int i, int j)
    {
        char c;
        c = a[i]; a[i] = a[j]; a[j] = c;
    }

    // next higher permutation
    public static int nextPermutation (int number)
    {
        ArrayList<String> perm = new ArrayList<String>();

        String cur = ""+number;

        int nextPerm = 0;

        perm1(cur, perm);

        for (String s : perm)
        {
            if (Integer.parseInt(s) > number
                        && (nextPerm == 0 ||
                            Integer.parseInt(s) < nextPerm))
            {
                nextPerm = Integer.parseInt(s);
            }
        }

            return nextPerm;
    }
}

Teste:

public static void main(String[] args) 
{
    int a = 38276;

    int b = NumPermExample.nextPermutation(a);

    System.out.println("a: "+a+", b: "+b);
}
Khaled.K
fonte
0

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.

amador
fonte
1
Funciona, mas extremamente devagar. É um algoritmo de tempo exponencial em que isso pode ser resolvido em tempo linear.
interjay
0

Apenas outra solução usando python:

def PermutationStep(num):
    if sorted(list(str(num)), reverse=True) == list(str(num)):
        return -1
    ls = list(str(num))
    n = 0
    inx = 0
    for ind, i in enumerate(ls[::-1]):
        if i < n:
            n = i
            inx = -(ind + 1)
            break
        n = i
    ls[inx], ls[inx + 1] = ls[inx + 1], ls[inx]

    nl = ls[inx::-1][::-1]
    ln = sorted(ls[inx+1:])
    return ''.join(nl) + ''.join(ln)

print PermutationStep(23514)

Resultado:

23541
James Sapam
fonte
0
public static void findNext(long number){

        /* convert long to string builder */    

        StringBuilder s = new StringBuilder();
        s.append(number);
        int N = s.length();
        int index=-1,pivot=-1;

/* from tens position find the number (called pivot) less than the number in right */ 

        for(int i=N-2;i>=0;i--){

             int a = s.charAt(i)-'0';
             int b = s.charAt(i+1)-'0';

             if(a<b){
                pivot = a;
                index =i;
                break;
            }
        }

      /* if no such pivot then no solution */   

        if(pivot==-1) System.out.println(" No such number ")

        else{   

     /* find the minimum highest number to the right higher than the pivot */

            int nextHighest=Integer.MAX_VALUE, swapIndex=-1;

            for(int i=index+1;i<N;i++){

            int a = s.charAt(i)-'0';

            if(a>pivot && a<nextHighest){
                    nextHighest = a;
                    swapIndex=i;
                }
            }


     /* swap the pivot and next highest number */

            s.replace(index,index+1,""+nextHighest);
            s.replace(swapIndex,swapIndex+1,""+pivot);

/* sort everything to right of pivot and replace the sorted answer to right of pivot */

            char [] sort = s.substring(index+1).toCharArray();
            Arrays.sort(sort);

            s.replace(index+1,N,String.copyValueOf(sort));

            System.out.println("next highest number is "+s);
        }

    }
sreeprasad
fonte
0

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.

/**
 * 
 * Inserts a integer at any index around string.
 * 
 * @param number
 * @param position
 * @param item
 * @return
 */
public String insertToNumberStringAtPosition(String number, int position,
        int item) {
    String temp = null;
    if (position >= number.length()) {
        temp = number + item;
    } else {
        temp = number.substring(0, position) + item
                + number.substring(position, number.length());
    }
    return temp;
}

/**
 * To generate permutations of a number.
 * 
 * @param number
 * @return
 */
public List<String> permuteNumber(String number) {
    List<String> permutations = new ArrayList<String>();
    if (number.length() == 1) {
        permutations.add(number);
        return permutations;
    }
    // else
    int inserterDig = (int) (number.charAt(0) - '0');
    Iterator<String> iterator = permuteNumber(number.substring(1))
            .iterator();
    while (iterator.hasNext()) {
        String subPerm = iterator.next();
        for (int dig = 0; dig <= subPerm.length(); dig++) {
            permutations.add(insertToNumberStringAtPosition(subPerm, dig,
                    inserterDig));
        }
    }
    return permutations;
}
shashi
fonte
0
#include<bits/stdc++.h>
using namespace std;
int main() 
{
    int i,j,k,min,len,diff,z,u=0,f=0,flag=0;
    char temp[100],a[100]`enter code here`,n;
    min=9999;
    //cout<<"Enter the number\n";
    cin>>a;
    len=strlen(a);
    for(i=0;i<len;i++)
    {
        if(a[i]<a[i+1]){flag=1;break;}
    }
    if(flag==0){cout<<a<<endl;}
    else
    {
        for(i=len-1;i>=0;i--)if(((int)a[i-1])<((int)a[i]))break;
        for(k=0;k<i-1;k++)cout<<a[k];
        for(j=i;j<len;j++)
        {
            if(((int)a[j]-48)-((int)a[i-1]-48)>0)
            {
                diff=((int)a[j]-48)-((int)a[i-1]-48);
                if(diff<min){n=a[j];min=diff;}
            }
        }
        cout<<n;
        for(z=i-1;z<len;z++)
        {
            temp[u]=a[z];
            u++;
        }
        temp[u]='\0';
        sort(temp,temp+strlen(temp));
        for(z=0;z<strlen(temp);z++){if(temp[z]==n&&f==0){f=1;continue;}cout<<temp[z];}
    }
    return 0;
}
Ujjwal Gulecha
fonte
0

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:

  1. Permita todas as coisas e escolha min mais alto: O (n!)

  2. 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).


import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

import org.junit.Test;

import static org.junit.Assert.assertEquals;

public class NextHigherSameDigits {

    public long next(final long num) {
        final char[] chars = String.valueOf(num).toCharArray();
        final int[] digits = new int[chars.length];
        for (int i = 0; i < chars.length; i++) {
            digits[i] = Character.getNumericValue(chars[i]);
        }

        final Map<Integer, Integer> indexToIndexOfNextSmallerLeft = new HashMap<>();
        indexToIndexOfNextSmallerLeft.put(1, digits[1] > digits[0] ? 0 : null);
        for (int i = 2; i < digits.length; i++) {
            final int left = digits[i - 1];
            final int current = digits[i];
            Integer indexOfNextSmallerLeft = null;
            if (current > left) {
                indexOfNextSmallerLeft = i - 1;
            } else {
                final Integer indexOfnextSmallerLeftOfLeft = indexToIndexOfNextSmallerLeft.get(i - 1);
                final Integer nextSmallerLeftOfLeft = indexOfnextSmallerLeftOfLeft == null ? null : 
                    digits[indexOfnextSmallerLeftOfLeft];

                if (nextSmallerLeftOfLeft != null && current > nextSmallerLeftOfLeft) {
                    indexOfNextSmallerLeft = indexOfnextSmallerLeftOfLeft;
                } else {
                    indexOfNextSmallerLeft = null;
                }
            }

            indexToIndexOfNextSmallerLeft.put(i, indexOfNextSmallerLeft);
        }

        Integer maxOfindexOfNextSmallerLeft = null;
        Integer indexOfMinToSwapWithNextSmallerLeft = null;
        for (int i = digits.length - 1; i >= 1; i--) {
            final Integer indexOfNextSmallerLeft = indexToIndexOfNextSmallerLeft.get(i);
            if (maxOfindexOfNextSmallerLeft == null ||
                    (indexOfNextSmallerLeft != null && indexOfNextSmallerLeft > maxOfindexOfNextSmallerLeft)) {

                maxOfindexOfNextSmallerLeft = indexOfNextSmallerLeft;
                if (maxOfindexOfNextSmallerLeft != null && (indexOfMinToSwapWithNextSmallerLeft == null || 
                        digits[i] < digits[indexOfMinToSwapWithNextSmallerLeft])) {

                    indexOfMinToSwapWithNextSmallerLeft = i;
                }
            }
        }

        if (maxOfindexOfNextSmallerLeft == null) {
            return -1;
        } else {
            swap(digits, indexOfMinToSwapWithNextSmallerLeft, maxOfindexOfNextSmallerLeft);
            reverseRemainingOfArray(digits, maxOfindexOfNextSmallerLeft + 1);
            return backToLong(digits);
        }
    }

    private void reverseRemainingOfArray(final int[] digits, final int startIndex) {
        final int[] tail = Arrays.copyOfRange(digits, startIndex, digits.length);
        for (int i = tail.length - 1; i >= 0; i--) {
            digits[(digits.length - 1)  - i] = tail[i];                 
        }
    }

    private void swap(final int[] digits, final int currentIndex, final int indexOfNextSmallerLeft) {
        int temp = digits[currentIndex];
        digits[currentIndex] = digits[indexOfNextSmallerLeft];
        digits[indexOfNextSmallerLeft] = temp;
    }

    private long backToLong(int[] digits) {     
        StringBuilder sb = new StringBuilder();
        for (long i : digits) {
            sb.append(String.valueOf(i));
        }

        return Long.parseLong(sb.toString());
    }

    @Test
    public void test() {
        final long input1 =    34722641;
        final long expected1 = 34724126;
        final long output1 = new NextHigherSameDigits().next(input1);
        assertEquals(expected1, output1);

        final long input2 =    38276;
        final long expected2 = 38627;
        final long output2 = new NextHigherSameDigits().next(input2);
        assertEquals(expected2, output2);

        final long input3 =    54321;
        final long expected3 = -1;
        final long output3 = new NextHigherSameDigits().next(input3);
        assertEquals(expected3, output3);

        final long input4 =    123456784987654321L;
        final long expected4 = 123456785123446789L;
        final long output4 = new NextHigherSameDigits().next(input4);
        assertEquals(expected4, output4);

        final long input5 =    9999;
        final long expected5 = -1;
        final long output5 = new NextHigherSameDigits().next(input5);
        assertEquals(expected5, output5);
    }

}
PoweredByRice
fonte
0

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

int getNextNumber(int input)
{
    int flipPosition=0;
    int trailingZeros=0;
    int trailingOnes=0;
    int copy = input;

    //count trailing zeros
    while(copy != 0 && (copy&1) == 0 )
    {
        ++trailingZeros;

        //test next bit
        copy = copy >> 1;
    }

    //count trailing ones
    while(copy != 0 && (copy&1) == 1 )
    {
        ++trailingOnes;

        //test next bit
        copy = copy >> 1;
    }

    //if we have no 1's (i.e input is 0) we cannot form another pattern with 
    //the same number of 1's which will increment the input, or if we have leading consecutive
    //ones followed by consecutive 0's up to the maximum bit size of a int
    //we cannot increase the input whilst preserving the original no of 0's and
    //1's in the bit pattern
    if(trailingZeros + trailingOnes  == 0 || trailingZeros + trailingOnes == 31)
        return -1;

    //flip first 0 followed by a 1 found from the right of the bit pattern
    flipPosition = trailingZeros + trailingOnes+1;
    input |= 1<<(trailingZeros+trailingOnes);

    //clear fields to the right of the flip position
    int mask = ~0 << (trailingZeros+trailingOnes);
    input &= mask;

    //insert a bit pattern to the right of the flip position that will contain
    //one less 1 to compensate for the bit we switched from 0 to 1
    int insert = flipPosition-1;
    input |= insert;

    return input;
}
gilla07
fonte
0
int t,k,num3,num5;
scanf("%d",&t);
int num[t];
for(int i=0;i<t;i++){
    scanf("%d",&num[i]);   
}
for(int i=0;i<t;i++){
    k=(((num[i]-1)/3)+1); 
    if(k<0)
        printf("-1");
    else if(num[i]<3 || num[i]==4 || num[i]==7)
        printf("-1");
    else{
        num3=3*(2*num[i] - 5*k);
        num5=5*(3*k -num[i]);
        for(int j=0;j<num3;j++)
            printf("5");
        for(int j=0;j<num5;j++)
            printf("3");
    }
    printf("\n");
}
Prakhar Srivastava
fonte
0

Aqui está a implementação Java

public static int nextHigherNumber(int number) {
    Integer[] array = convertToArray(number);
    int pivotIndex = pivotMaxIndex(array);
    int digitInFirstSequence = pivotIndex -1;
    int lowerDigitIndexInSecondSequence = lowerDigitIndex(array[digitInFirstSequence], array, pivotIndex);
    swap(array, digitInFirstSequence, lowerDigitIndexInSecondSequence);
    doRercursiveQuickSort(array, pivotIndex, array.length - 1);
    return arrayToInteger(array);
}

public static Integer[] convertToArray(int number) {
    int i = 0;
    int length = (int) Math.log10(number);
    int divisor = (int) Math.pow(10, length);
    Integer temp[] = new Integer[length + 1];

    while (number != 0) {
        temp[i] = number / divisor;
        if (i < length) {
            ++i;
        }
        number = number % divisor;
        if (i != 0) {
            divisor = divisor / 10;
        }
    }
    return temp;
}

private static int pivotMaxIndex(Integer[] array) {
    int index = array.length - 1;
    while(index > 0) {
        if (array[index-1] < array[index]) {
            break;
        }
        index--;
    }       
    return index;
}

private static int lowerDigitIndex(int number, Integer[] array, int fromIndex) {
    int lowerMaxIndex = fromIndex;
    int lowerMax = array[lowerMaxIndex];
    while (fromIndex < array.length - 1) {
        if (array[fromIndex]> number && lowerMax > array[fromIndex]) {
            lowerMaxIndex = fromIndex; 
        }
        fromIndex ++;
    }
    return lowerMaxIndex;
}

public static int arrayToInteger(Integer[] array) {
    int number = 0;
    for (int i = 0; i < array.length; i++) {
        number+=array[i] * Math.pow(10, array.length-1-i);
    }
    return number;
}

Aqui estão os testes de unidade

@Test
public void nextHigherNumberTest() {
    assertThat(ArrayUtils.nextHigherNumber(34722641), is(34724126));
    assertThat(ArrayUtils.nextHigherNumber(123), is(132));
}
craftsmannadeem
fonte
0

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.

class Program
{
    static void Main(string[] args)
    {

        int inputNumber = 629;
        int i, currentIndexOfNewArray = 0;

        int[] arrayOfInput = GetIntArray(inputNumber);
        var numList = arrayOfInput.ToList();

        int[] newArray = new int[arrayOfInput.Length];

        do
        {
            int temp = 0;
            int digitFoundAt = 0;
            for (i = numList.Count; i > 0; i--)
            {
                if (numList[i - 1] > temp)
                {
                    temp = numList[i - 1];
                    digitFoundAt = i - 1;
                }
            }

            newArray[currentIndexOfNewArray] = temp;
            currentIndexOfNewArray++;
            numList.RemoveAt(digitFoundAt);
        } while (arrayOfInput.Length > currentIndexOfNewArray);



        Console.WriteLine(GetWholeNumber(newArray));

        Console.ReadKey();


    }

    public static int[] GetIntArray(int num)
    {
        IList<int> listOfInts = new List<int>();
        while (num > 0)
        {
            listOfInts.Add(num % 10);
            num = num / 10;
        }
        listOfInts.Reverse();
        return listOfInts.ToArray();
    }

    public static double GetWholeNumber(int[] arrayNumber)
    {
        double result = 0;
        double multiplier = 0;
        var length = arrayNumber.Count() - 1;
        for(int i = 0; i < arrayNumber.Count(); i++)
        {
            multiplier = Math.Pow(10.0, Convert.ToDouble(length));
            result += (arrayNumber[i] * multiplier);
            length = length - 1;
        }

        return result;
    }
}
Arul
fonte
0

Implementação muito simples usando Javascript, próximo número mais alto com os mesmos dígitos

/*
Algorithm applied
I) Traverse the given number from rightmost digit, keep traversing till you find a digit which is smaller than the previously traversed digit. For example, if the input number is “534976”, we stop at 4 because 4 is smaller than next digit 9. If we do not find such a digit, then output is “Not Possible”.

II) Now search the right side of above found digit ‘d’ for the smallest digit greater than ‘d’. For “534976″, the right side of 4 contains “976”. The smallest digit greater than 4 is 6.

III) Swap the above found two digits, we get 536974 in above example.

IV) Now sort all digits from position next to ‘d’ to the end of number. The number that we get after sorting is the output. For above example, we sort digits in bold 536974. We get “536479” which is the next greater number for input 534976.

*/

function findNext(arr)
{
  let i;
  //breaking down a digit into arrays of string and then converting back that array to number array
  let arr1=arr.toString().split('').map(Number) ;
  //started to loop from the end of array 
  for(i=arr1.length;i>0;i--)
  {
    //looking for if the current number is greater than the number next to it
    if(arr1[i]>arr1[i-1])
    {// if yes then we break the loop it so that we can swap and sort
      break;}
  }

  if(i==0)
  {console.log("Not possible");}

   else
  {
   //saving that big number and smaller number to the left of it
   let smlNum =arr1[i-1];
    let bigNum =i;
   /*now looping again and checking if we have any other greater number, if we have one AFTER big number and smaller number to the right. 
     A greater number that is of course greater than that smaller number but smaller than the first number we found.
     Why are doing this? Because that is an algorithm to find next higher number with same digits. 
   */
    for(let j=i+1;j<arr1.length;j++)
      {//What if there are no digits afters those found numbers then of course loop will not be initiated otherwise...
        if(arr1[j]> smlNum && arr1[j]<arr1[i])
        {// we assign that other found number here and replace it with the one we found before
          bigNum=j;

        }
      } //now we are doing swapping of places the small num and big number , 3rd part of alogorithm
    arr1[i-1]=arr1[bigNum];
          arr1[bigNum]=smlNum;
    //returning array 
    //too many functions applied sounds complicated right but no, here is the  trick
    //return arr first then apply each function one by one to see output and then further another func to that output to match your needs
    // so here after swapping , 4th part of alogorithm is to sort the array right after the 1st small num we found
    // to do that first we simple take part of array, we splice it and then we apply sort fucntion, then check output (to check outputs, pls use chrome dev console)
    //and then  simply the rest concat and join to main one digit again.
     return arr1.concat((arr1.splice(i,arr1.length)).sort(function(a, b){return a-b})).join('');



    // Sorry to make it too long but its fun explaining things in much easier ways as much as possible!!
  }

}


findNext(1234);

Como existem muitos comentários, é melhor copiá-lo para o seu editor de texto. Obrigado!

pulkit219
fonte
0

Há muitas boas respostas, mas não encontrei uma implementação decente de Java. Aqui estão meus dois centavos:

public void findNext(int[] nums) {
    int i = nums.length - 1;
    // nums[i - 1] will be the first non increasing number
    while (i > 0 && nums[i] <= nums[i - 1]) {
        i--;
    }
    if (i == 0) {
        System.out.println("it has been the greatest already");
    } else {
        // Find the smallest digit in the second sequence that is larger than it:
        int j = nums.length - 1;
        while (j >= 0 && nums[j] < nums[i - 1]) {
            j--;
        }
        swap(nums, i - 1, j);
        Arrays.sort(nums, i, nums.length);
        System.out.println(Arrays.toString(nums));
    }
}

public void swap(int[] nums, int i, int j) {
    int tmp = nums[i];
    nums[i] = nums[j];
    nums[j] = tmp;
}
Patrick
fonte
0
#include<stdio.h>
#include<cstring>
#include<iostream>
#include<string.h>
#include<sstream>
#include<iostream>

using namespace std;
int compare (const void * a, const void * b)
{
    return *(char*)a-*(char*)b;
}

/*-----------------------------------------------*/

int main()
{
    char number[200],temp;
    cout<<"please enter your number?"<<endl;
    gets(number);
    int n=strlen(number),length;
    length=n;
    while(--n>0)
    {
        if(number[n-1]<number[n])
        {
            for(int i=length-1;i>=n;i--)
            {
                if(number[i]>number[n-1])
                {
                    temp=number[i];
                    number[i]=number[n-1];
                    number[n-1]=temp;
                    break;
                }
            }
            qsort(number+n,length-n,sizeof(char),compare);
            puts(number); 
            return 0;
        }
    }
    cout<<"sorry itz the greatest one :)"<<endl;
}
Anshika Agrawal
fonte