Dado un número, encuentre el siguiente número más alto que tenga exactamente el mismo conjunto de dígitos que el número original

226

Acabo de bombardear una entrevista e hice casi cero progreso en mi pregunta de entrevista. ¿Alguien puede decirme cómo hacer esto? Intenté buscar en línea pero no pude encontrar nada:

Dado un número, encuentre el siguiente número más alto que tenga exactamente el mismo conjunto de dígitos que el número original. Por ejemplo: dado 38276 retorno 38627

Quería comenzar por encontrar el índice del primer dígito (desde la derecha) que fuera menor que el dígito de las unidades. Luego rotaría los últimos dígitos del subconjunto de modo que fuera el siguiente número más grande compuesto por los mismos dígitos, pero se atascó.

El entrevistador también sugirió intentar cambiar los dígitos de uno en uno, pero no pude descifrar el algoritmo y simplemente miré una pantalla durante unos 20-30 minutos. No hace falta decir que creo que voy a tener que continuar la búsqueda de empleo.

editar: por lo que vale, me invitaron a la próxima ronda de entrevistas

bhan
fuente
15
sin pensar demasiado en ello, al menos sería una fuerza bruta calcular todas las permutaciones de los dígitos y obtener el número mínimo que es mayor que el número de entrada
BrokenGlass
13
en C ++ sólo se puede utilizar next_permutation;-)
thedayturns
99
Para su información, así es como lo resolví en aproximadamente 15 minutos mientras apenas pensaba en el problema: primero pasé 5 minutos escribiendo un algoritmo de fuerza bruta que acaba de crear todas las permutaciones posibles de un conjunto de dígitos, los ordenó y los mostró. Pasé 5 minutos revisando esos datos hasta que surgió un patrón de la lista (la solución aceptada por O (n) aquí se hizo evidente después de un breve tiempo buscando), luego pasé 5 minutos codificando el algoritmo O (n).
Ben Lee
1
En general, esta no es una mala manera de encontrar algoritmos para resolver este tipo de problema cuando está atascado: use la fuerza bruta en una muestra pequeña para crear una gran cantidad de datos que luego puede usar para ver patrones más fácilmente.
Ben Lee
19
También me gustaría señalar, si realmente no puede encontrar una manera eficiente de hacer esto, no hacer nada es una forma segura de fallar la entrevista (y en el mundo de los negocios, es una forma segura de perder una fecha límite de producto) . Cuando te quedaste atascado, en lugar de darte por vencido, deberías haberlo forzado y poner un comentario en la parte superior "TODO: refactorizar el rendimiento" o algo así. Si estuviera entrevistando y alguien hiciera eso, no necesariamente les fallaría. Al menos se les ocurrió algo que funcionó Y reconocieron que había algo mejor por ahí, incluso si no podían encontrarlo.
Ben Lee

Respuestas:

272

Puede hacerlo en O(n)(donde nestá el número de dígitos) así:

Comenzando por la derecha, encontrará el primer par de dígitos de modo que el dígito izquierdo sea más pequeño que el dígito derecho. Vamos a referirnos al dígito izquierdo por "dígito-x". Encuentre el número más pequeño más grande que digit-x a la derecha de digit-x, y colóquelo inmediatamente a la izquierda de digit-x. Finalmente, clasifique los dígitos restantes en orden ascendente, ya que ya estaban en orden descendente , todo lo que necesita hacer es invertirlos (guarde para el dígito-x, que se puede colocar en el lugar correcto O(n)) .

Un ejemplo lo aclarará más:

123456784987654321
comenzar con un número

123456784 987654321
         ^ el primer lugar desde la derecha donde el dígito izquierdo es menor que el derecho  
         El dígito "x" es 4

123456784 987654321
              ^ encuentre el dígito más pequeño más grande que 4 a la derecha

123456785 4 98764321
        ^ colóquelo a la izquierda de 4

123456785 4 12346789
123456785123446789
         ^ ordene los dígitos a la derecha de 5. Ya que todos excepto 
         los '4' ya estaban en orden descendente, todo lo que tenemos que hacer es 
         invierta su orden y encuentre el lugar correcto para el '4'

Prueba de corrección:

Usemos letras mayúsculas para definir cadenas de dígitos y minúsculas para los dígitos. La sintaxis ABsignifica "la concatenación de cadenas Ay B" . <es el ordenamiento lexicográfico, que es lo mismo que el ordenamiento de enteros cuando las cadenas de dígitos son de igual longitud.

Nuestro número original N es de la forma AxB, donde xes un solo dígito y Bse ordena descendente.
El número encontrado por nuestro algoritmo es AyC, donde y ∈ Bes el dígito más pequeño > x (debe existir debido a la forma en que xse eligió, ver arriba) , y Cse ordena de forma ascendente.

Suponga que hay algún número (usando los mismos dígitos) N'tal que AxB < N' < AyC. N'debe comenzar con Ao de lo contrario no podría caer entre ellos, para que podamos escribirlo en el formulario AzD. Ahora nuestra desigualdad es AxB < AzD < AyC, que es equivalente a xB < zD < yCdonde las cadenas de tres dígitos contienen los mismos dígitos.

Para que eso sea cierto, debemos tenerlo x <= z <= y. Puesto que yes el dígito más pequeño > x, zno puede ser de entre ellos, así que o z = xo z = y. Decir z = x. Entonces nuestra desigualdad es xB < xD < yC, lo que significa B < Dque tanto By Dtienen los mismos dígitos. Sin embargo, B se ordena descendente, por lo que no hay una cadena con esos dígitos más grandes que ella. Por lo tanto no podemos tener B < D. Siguiendo los mismos pasos, vemos que si z = y, no podemos tener D < C.

Por N'lo tanto , no puede existir, lo que significa que nuestro algoritmo encuentra correctamente el siguiente número más grande.

BlueRaja - Danny Pflughoeft
fuente
77
buena solución! tengo una pregunta diga "el dígito más pequeño más grande que x" es y. ¿podemos intercambiar x e y, luego invertir x.index + 1 -> end?
Kent
8
¿Qué le sucede al número 99999?
Sterex
19
@ Sterex, no es solo 99999; cualquier número cuyos dígitos ya estén completamente ordenados en orden descendente es el máximo (por lo que 98765 tampoco tiene solución, por ejemplo). Esto es fácil de detectar programáticamente porque el paso 1 del algoritmo fallará (no hay un par de dígitos consecutivos de modo que "el dígito izquierdo sea más pequeño que el derecho").
Ben Lee
3
@ TMN: 9 es mayor que 8, por lo que debe mover 9 a la izquierda de 8: 9 832luego ordenar todo a la derecha de 9:9238
BlueRaja - Danny Pflughoeft
44
@Kent para que su solución funcione, tendrá que cambiar encontrar el dígito más pequeño más grande que 4 a la derecha para encontrar el dígito más pequeño más grande que 4 a la derecha . De lo contrario, por ejemplo, 1234567849876 55 4321 dará como resultado 1234567851234 54 6789 (en lugar de 1234567851234 45 6789). Una trampa :-)
osundblad 01 de
94

Un problema casi idéntico apareció como un problema de Code Jam y tiene una solución aquí:

http://code.google.com/codejam/contest/dashboard?c=186264#s=a&a=1

Aquí hay un resumen del método usando un ejemplo:

34722641

A. Divida la secuencia de dígitos en dos, de modo que la parte derecha sea lo más larga posible mientras permanezca en orden decreciente:

34722 641

(Si el número completo está en orden decreciente, no se puede hacer un número mayor sin agregar dígitos).

B.1 Seleccione el último dígito de la primera secuencia:

3472(2) 641

B.2 Encuentre el dígito más pequeño en la segunda secuencia que sea más grande que él:

3472(2) 6(4)1

B.3 Intercambiarlos:

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

C. Ordenar la segunda secuencia en orden creciente:

34724 126

D. ¡Listo!

34724126
Weeble
fuente
1
Error tipográfico allí: creo que "-> 34721 621" debería ser "-> 34724 621"?
bjnord
1
@bjnord Buena captura. Fijo. No estoy seguro de cómo lo logré, fue correcto en las líneas posteriores.
Weeble
+1 La mejor respuesta aquí. Intuitivo y rápido. (también es en lo que pensé cuando
resolví
1
@Neel: en el paso C, los dígitos que queremos ordenar están en orden descendente, excepto el dígito que intercambiamos en el paso B. Para ordenarlos, en realidad solo necesitamos invertirlos y colocar el dígito intercambiado en la posición correcta. Esto es lo que describe BlueRaja.
Weeble
1
@Dhavaldave ¿Cuál es el problema? En el paso A obtienes "12" y "3". En el paso B obtienes "13" y "2". En el paso C nada cambia. En el paso D obtienes "132". El único caso en el que no obtendrá una respuesta es cuando el número ya es el máximo posible, por ejemplo, "321". En ese caso, el paso A le da "" y "321", y no puede continuar con una secuencia vacía para el lado izquierdo de la división.
Weeble
14

Aquí hay una solución compacta (pero en parte fuerza bruta) en Python

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

En C ++, podría realizar las permutaciones de esta manera: https://stackoverflow.com/a/9243091/1149664 (es el mismo algoritmo que el de itertools)

Aquí hay una implementación de la respuesta superior descrita por Weeble y BlueRaja, (otras respuestas). Dudo que haya algo mejor.

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
fuente
¿Hay alguna posibilidad de que alguien pueda actualizar esto, por favor? No parece funcionar en Python 3 como se muestra type 'map' has no len(). Simplemente cambiaría la segunda línea a iis=list(map(int,str(ii))). ¿Y alguien podría explicar la if i == 0: return iilínea por favor? ¿Por qué funcionaría con entradas como 111 o 531? Gracias.
Bowen Liu el
Lo arreglé para python 3 ahora agregando ´list () a iis = ... ´. Los casos 111 y 531 no tienen solución, pero mi implementación devuelve 111 y 531 para esos. Puede cambiar eso a una excepción de lo que encuentra que es mejor cambiando esa línea i == 0.
Johan Lundberg el
Gracias. De hecho, realizo un bucle en la otra dirección, así que me confundí con i == 0, mientras que en mi situación lo será i == len(iis).
Bowen Liu
8

Como mínimo, aquí hay un par de soluciones basadas en String de fuerza bruta, que deberías haber sido capaz de encontrar desde la parte superior de tu cabeza:

la lista de dígitos 38276ordenados es23678

la lista de dígitos 38627ordenados es23678

Incremento de fuerza bruta, clasificación y comparación

A lo largo de la fuerza bruta, las soluciones se convertirían en una Cadena y fuerza bruta todos los números posibles usando esos dígitos.

Cree entradas a partir de todas ellas, colóquelas en una lista y ordénelas, obtenga la siguiente entrada después de la entrada de destino.

Si pasaste 30 minutos en esto y no lograste al menos un enfoque de fuerza bruta, tampoco te contrataría.

En el mundo de los negocios, una solución que es poco elegante, lenta y torpe pero que hace el trabajo siempre es más valiosa que ninguna solución, de hecho, que describe prácticamente todo el software de negocios, poco elegante, lento y torpe.


fuente
1
Bueno, mi primer comentario fuera del bate fue "Podría hacerlo por fuerza bruta pero ...". Si realmente no hay una solución algorítmica, estoy un poco decepcionado
bhan
44
Si yo fuera el entrevistador, no estaría tan feliz con un enfoque de fuerza bruta.
Ahmad Y. Saleh
@benjamin han, hay una solución algorítmica. Sigue intercambiando dígitos desde la derecha, hasta que encuentres el resultado. No hay necesidad de calcular todos los permutatnios antes.
dantuch
77
Ciertamente, hay soluciones mucho mejores que la fuerza bruta, por ejemplo, ardendertat.com/2012/01/02/…
BrokenGlass
@BrokenGlass Definitivamente una solución mucho mejor. Se me ocurrió esa idea y luego publicaste el 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
fuente
Se me ocurrió esta solución. Por favor, si tiene alguna pregunta, pregunte.
Ashikodi
4

Tu idea

Quería comenzar por encontrar el índice del primer dígito (desde la derecha) que fuera menor que el dígito de las unidades. Luego rotaría los últimos dígitos del subconjunto de modo que fuera el siguiente número más grande compuesto por los mismos dígitos, pero se atascó.

está bastante bien, en realidad. Solo tiene que considerar no solo el último dígito, sino todos los dígitos de menor importancia que el actualmente considerado. Desde antes de que se alcance eso, tenemos una secuencia monotónica de dígitos, que es el dígito más a la derecha más pequeño que su vecino derecho. Considerar

1234675
    ^

El siguiente número más grande que tiene los mismos dígitos es

1234756

El dígito encontrado se intercambia por el último dígito, el más pequeño de los dígitos considerados, y los dígitos restantes se ordenan en orden creciente.

Daniel Fischer
fuente
4

Estoy bastante seguro de que su entrevistador estaba tratando de empujarlo suavemente hacia algo como esto:

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);

No es necesariamente la solución más eficiente o elegante, pero resuelve el ejemplo proporcionado en dos ciclos y cambia los dígitos uno a la vez como sugirió.

Lex R
fuente
2

Toma un número y divídelo en dígitos. Entonces, si tenemos un número de 5 dígitos, tenemos 5 dígitos: abcde

Ahora intercambie dye y compare con el número original, si es más grande, tiene su respuesta.

Si no es más grande, cambie e y c. Ahora compare y si es más pequeño intercambie dye nuevamente (observe la recursividad), tome el más pequeño.

Continúe hasta que encuentre un número mayor. Con la recursividad, debería funcionar como unas 9 líneas de esquema, o 20 de c #.

Roland
fuente
2

Esa es una pregunta muy interesante.

Aquí está mi versión de Java. Tómeme aproximadamente 3 horas desde que descubrí el patrón para terminar completamente el código antes de revisar los comentarios de otros colaboradores. Me alegra ver que mi idea es la misma con los demás.

O (n) solución. Honestamente, fracasaré en esta entrevista si el tiempo es de solo 15 minutos y requiero terminar el código completo en la pizarra.

Aquí hay algunos puntos interesantes para mi solución:

  • Evita cualquier clasificación.
  • Evite la operación de la cadena por completo
  • Lograr la complejidad del espacio O (logN)

Puse comentarios detallados en mi código, y el Big O en cada paso.

  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;

}

Aquí está el resultado que se ejecuta en Intellj:

959879532-->959892357
1358642-->1362458
1234567-->1234576
77654321-->77654321
38276-->38627
47-->74
Boveyking
fuente
en el caso 123, ¿cuál será la respuesta? Prácticamente el código no generará salida mientras debe venir 132
Dhaval dave
2

Una implementación de JavaScript del algoritmo de @ 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
fuente
1

Una solución (en Java) podría ser la siguiente (estoy seguro de que los amigos aquí pueden encontrar una mejor):
Comience a intercambiar dígitos desde el final de la cadena hasta obtener un número más alto.
Es decir, primero comienza a subir el dígito inferior, luego el siguiente más alto, etc.
Luego ordena el resto. En su ejemplo obtendría:

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));
}
Cratilo
fuente
@yi_H: La salida es. ¿ 63872Por qué, qué debería ser?
Cratylus
bueno .. siguiente numero mas alto? :) ese era el requisito, ¿no?
Karoly Horvath
@BlueRaja - Danny Pflughoeft: Gracias por su ayuda. Cambié el código de la siguiente manera: Mueva el menor dígito por adelantado (lo que arroje un número más alto) y clasifique el resto
Cratylus
1

Si está programando en C ++, puede 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
fuente
¿Qué pasa si ingreso 100? :-)
jweyrich
1

No sabía nada sobre el algoritmo de fuerza bruta cuando respondí esta pregunta, así que lo enfoqué desde otro ángulo. Decidí buscar en toda la gama de posibles soluciones en las que este número podría reorganizarse, comenzando desde number_given + 1 hasta el número máximo disponible (999 para un número de 3 dígitos, 9999 para 4 dígitos, etc.). Hice este tipo de búsqueda de un palíndromo con palabras, ordenando los números de cada solución y comparándolo con el número ordenado dado como parámetro. Entonces simplemente devolví la primera solución en la matriz de soluciones, ya que este sería el siguiente valor posible.

Aquí está mi código en 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
fuente
¿Cuál es la complejidad temporal de esta solución?
Nitish Upreti
@ Myth17 No estoy seguro, ya que nunca lo probé. Sin embargo, si desea resolverlo, consulte esta publicación: 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 a tope
fuente
0

Solo he probado esto con dos números. Ellos trabajaron. Como gerente de TI durante 8 años hasta que me jubilé en diciembre pasado, me preocupaban tres cosas: 1) Precisión: es bueno si funciona, siempre. 2) Velocidad: debe ser aceptable para el usuario. 3) Claridad: probablemente no soy tan inteligente como tú, pero te pago. Asegúrate de explicar lo que estás haciendo, en inglés.

Omar, mucha suerte en el futuro.

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
fuente
0

Aquí está mi código, es una versión modificada de este ejemplo.

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;
    }
}

Prueba:

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

    int b = NumPermExample.nextPermutation(a);

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

Agregue 9 al número de n dígitos dado. Luego verifique si está dentro del límite (el primer número de dígitos (n + 1)). Si es así, verifique si los dígitos del nuevo número son los mismos que los dígitos del número original. Repita agregando 9 hasta que ambas condiciones sean verdaderas. Detenga el algo cuando el número vaya más allá del límite.

No pude encontrar un caso de prueba contradictorio para este método.

aficionado
fuente
1
Funciona, pero extremadamente lento. Es un algoritmo de tiempo exponencial donde esto podría resolverse en tiempo lineal.
Interjay
0

Solo otra solución 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)

Salida:

23541
James Sapam
fuente
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
fuente
0

A continuación se muestra el código para generar todas las permutaciones de un número ... aunque primero hay que convertir ese entero en una cadena usando String.valueOf (entero).

/**
 * 
 * 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
fuente
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
fuente
0

Otra implementación de Java, ejecutable de fábrica y completada con pruebas. Esta solución es O (n) espacio y tiempo utilizando una buena programación dinámica antigua.

Si uno quiere fuerza bruta, hay 2 tipos de fuerza bruta:

  1. Permuta todas las cosas, luego elige min más alto: O (n!)

  2. Similar a esta implementación, pero en lugar de DP, la ejecución bruta del paso de poblar el mapa indexToIndexOfNextSmallerLeft se ejecutará en 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
fuente
0

Necesitamos encontrar el bit 0 más correcto seguido de un 1 y voltear este bit 0 más a la derecha a 1.

por ejemplo, digamos que nuestra entrada es 487, que es 111100111 en binario.

volteamos el 0 más a la derecha que tiene 1 siguiendo

entonces obtenemos 111101111

pero ahora tenemos un 1 adicional y uno menos 0, por lo que reducimos el número de 1 a la derecha del bit flip en 1 y aumentamos el número de 0 bits en 1, produciendo

111101011 - binario 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
fuente
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
fuente
0

Aquí está la implementación de 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;
}

Aquí están las pruebas unitarias

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

Sé que esta es una pregunta muy antigua, pero aún así no encontré un código fácil en C #. Esto podría ayudar a los chicos que asisten a las 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
fuente
0

Implementación muy simple usando Javascript, el siguiente número más alto con los mismos 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 hay muchos comentarios, es mejor que puedas copiarlo en tu editor de texto. ¡Gracias!

pulkit219
fuente
0

Hay muchas buenas respuestas, pero no encontré una implementación decente de Java. Aquí están mis dos 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;
}
Patricio
fuente
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
fuente