Dato un numero, trova il prossimo numero più alto che ha esattamente lo stesso set di cifre del numero originale


226

Ho appena bombardato un'intervista e ho fatto praticamente zero progressi sulla mia domanda di intervista. Qualcuno può farmi sapere come fare? Ho provato a cercare online ma non sono riuscito a trovare nulla:

Dato un numero, trova il prossimo numero più alto che ha lo stesso insieme esatto di cifre del numero originale. Ad esempio: dato 38276 ritorno 38627

Volevo iniziare trovando l'indice della prima cifra (da destra) che era inferiore a quella. Quindi avrei ruotato le ultime cifre nel sottoinsieme in modo che fosse il numero più grande successivo composto dalle stesse cifre, ma mi sono bloccato.

L'intervistatore ha anche suggerito di provare a scambiare le cifre una alla volta, ma non sono riuscito a capire l'algoritmo e ho fissato uno schermo per circa 20-30 minuti. Inutile dire che penso che dovrò continuare la caccia al lavoro.

modifica: per quel che vale, sono stato invitato al prossimo round di interviste


15
senza pensarci troppo un inizio almeno sarebbe la forza bruta calcolare tutte le permutazioni delle cifre e prendere il numero minimo che è maggiore del numero di input
BrokenGlass

13
in C ++ è possibile utilizzare solo next_permutation;-)
thedayturns

9
Cordiali saluti, ecco come l'ho risolto in circa 15 minuti mentre pensavo a malapena al problema: per prima cosa ho trascorso 5 minuti a scrivere un algoritmo a forza bruta che ha appena creato tutte le possibili permutazioni di un set di cifre, le ha ordinate e visualizzate. Ho trascorso 5 minuti a esaminare quei dati fino a quando non è emerso un modello dall'elenco (la soluzione accettata O (n) qui è diventata chiara dopo poco tempo alla ricerca), quindi ho trascorso 5 minuti a codificare l'algoritmo O (n).
Ben Lee,

1
In generale, questo non è un brutto modo di escogitare algoritmi per risolvere questo tipo di problema quando si è bloccati: utilizzare la forza bruta su alcuni campioni di dimensioni ridotte per creare molti dati che è quindi possibile utilizzare per visualizzare più facilmente i motivi.
Ben Lee,

19
Vorrei anche sottolineare, se davvero non riesci a capire un modo efficace per farlo, non fare nulla è un modo sicuro per fallire l'intervista (e nel mondo degli affari, è un modo sicuro per non rispettare una scadenza del prodotto) . Quando ti sei bloccato, invece di mollare, avresti dovuto costringerlo bruto e mettere un commento in alto "TODO: refactor for performance" o qualcosa del genere. Se stavo intervistando e qualcuno lo facesse, non avrei necessariamente fallito. Almeno hanno escogitato qualcosa che ha funzionato E hanno riconosciuto che c'era qualcosa di meglio là fuori, anche se non riuscivano a trovarlo.
Ben Lee,

Risposte:


272

Puoi farlo in O(n)(dove nè il numero di cifre) in questo modo:

A partire da destra, trovi la prima coppia di cifre in modo tale che la cifra sinistra sia più piccola della cifra destra. Facciamo riferimento alla cifra sinistra con "cifra-x". Trova il numero più piccolo più grande di digit-x a destra di digit-x e posizionalo immediatamente a sinistra di digit-x. Infine, ordina le cifre rimanenti in ordine crescente - poiché erano già in ordine decrescente , tutto ciò che devi fare è invertirle (salvo per digit-x, che può essere posizionato nella posizione corretta in O(n)) .

Un esempio renderà questo più chiaro:

123.456.784.987,654321 millions
inizia con un numero

123456784 987654321
         ^ il primo posto da destra dove la cifra sinistra è inferiore alla destra  
         La cifra "x" è 4

123456784 987654321
              ^ trova la cifra più piccola più grande di 4 a destra

123456785 4 98764321
        ^ posizionalo a sinistra di 4

123456785 4 12346789
123.456.785.123,446789 millions
         ^ ordina le cifre a destra di 5. Poiché tutte tranne 
         i "4" erano già in ordine decrescente, tutto ciò che dobbiamo fare è 
         invertire il loro ordine e trovare il posto giusto per il "4"

Prova di correttezza:

Usiamo le lettere maiuscole per definire stringhe di cifre e lettere minuscole per le cifre. La sintassi ABsignifica "la concatenazione di stringhe Ae B" . <è l'ordinamento lessicografico, che è uguale all'ordinamento intero quando le stringhe di cifre hanno la stessa lunghezza.

Il nostro numero originale N è nella forma AxB, dove xè una singola cifra ed Bè ordinata in ordine decrescente.
Il numero trovato dal nostro algoritmo è AyC, dove y ∈ Bè la cifra più piccola > x (deve esistere a causa del modo in cui è xstata scelta, vedi sopra) , ed Cè ordinata in ordine crescente.

Supponiamo che ci sia un numero (usando le stesse cifre) N'tale che AxB < N' < AyC. N'deve iniziare Aaltrimenti altrimenti non potrebbe cadere tra di loro, quindi possiamo scriverlo nel modulo AzD. Ora la nostra disuguaglianza è AxB < AzD < AyC, che equivale a xB < zD < yCdove tutte e tre le stringhe di cifre contengono le stesse cifre.

Affinché ciò sia vero, dobbiamo avere x <= z <= y. Poiché yè la cifra più piccola > x, znon può essere tra loro, quindi o z = xo z = y. Say z = x. Quindi la nostra disuguaglianza è xB < xD < yC, il che significa B < Ddove entrambi Be Dhanno le stesse cifre. Tuttavia, B è ordinato in ordine decrescente, quindi non vi è alcuna stringa con quelle cifre più grandi di essa. Quindi non possiamo avere B < D. Seguendo gli stessi passaggi, vediamo che se z = y, non possiamo avere D < C.

Pertanto N'non può esistere, il che significa che il nostro algoritmo trova correttamente il numero più grande successivo.


7
bella soluzione! hai una domanda. dire "la cifra più piccola più grande di x" è y. possiamo semplicemente scambiare xey, quindi invertire x.index + 1 -> end?
Kent,

8
Cosa succede al numero 99999?
Sterex,

19
@Sterex, non è solo 99999; qualsiasi numero le cui cifre sono già completamente ordinate in ordine decrescente è il massimo (quindi anche 98765 non ha soluzione). Questo è facile da rilevare a livello di programmazione perché la fase 1 dell'algoritmo fallirà (non esiste una coppia di cifre consecutive tale che "la cifra sinistra è più piccola della cifra destra").
Ben Lee,

3
@TMN: 9 è più grande di 8, quindi dovresti spostare 9 a sinistra di 8: 9 832quindi ordina tutto a destra di 9:9238
BlueRaja - Danny Pflughoeft

4
@Kent per la soluzione di lavoro si dovrà cambiare trovare la più piccola cifra maggiore di 4 per il diritto per trovare la più piccola cifra maggiore di 4 da destra . Altrimenti, ad esempio, 1234567849876 55 4321 comporterà 1234567851234 54 6789 (anziché 1234567851234 45 6789). A nitpick :-)
osundblad

94

Un problema quasi identico è apparso come un problema di Code Jam e ha una soluzione qui:

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

Ecco un riepilogo del metodo usando un esempio:

34722641

A. Dividi la sequenza di cifre in due, in modo che la parte destra sia il più lunga possibile rimanendo in ordine decrescente:

34722 641

(Se l' intero numero è in ordine decrescente, non è possibile creare un numero più grande senza aggiungere cifre.)

B.1. Seleziona l'ultima cifra della prima sequenza:

3472(2) 641

B.2. Trova la cifra più piccola nella seconda sequenza più grande di essa:

3472(2) 6(4)1

B.3. Scambiali:

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

C. Ordinare la seconda sequenza in ordine crescente:

34724 126

D. Fatto!

34724126

1
Errore di battitura: penso che "-> 34721 621" dovrebbe essere "-> 34724 621"?
bjnord,

1
@bjnord Buona cattura. Fisso. Non sono sicuro di come ci sia riuscito: era corretto nelle righe successive.
Weeble,

+1 La migliore risposta qui. Intuitivo e veloce. (È anche quello a cui ho pensato quando ho lavorato su carta;))
Muhd,

1
@Neel - Nel passaggio C, le cifre che vogliamo ordinare sono in ordine decrescente, ad eccezione della cifra che abbiamo scambiato nel passaggio B. Per ordinarle, dobbiamo solo invertirle e riportare la cifra scambiata nella posizione giusta. Questo è ciò che descrive BlueRaja.
Weeble,

1
@Dhavaldave Qual è il problema? Nel passaggio A ottieni "12" e "3". Nel passaggio B ottieni "13" e "2". Nel passaggio C non cambia nulla. Nel passaggio D ottieni "132". L'unico caso in cui non otterrai una risposta è quando il numero è già il massimo possibile, ad esempio "321". In tal caso, il passaggio A ti dà "" e "321" e non puoi procedere con una sequenza vuota per il lato sinistro della divisione.
Weeble,

14

Ecco una soluzione compatta (ma in parte forza bruta) in Python

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

In C ++ potresti fare le permutazioni in questo modo: https://stackoverflow.com/a/9243091/1149664 (È lo stesso algoritmo di quello in itertools)

Ecco un'implementazione della risposta principale descritta da Weeble e BlueRaja, (altre risposte). Dubito che ci sia qualcosa di meglio.

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

Qualche possibilità che qualcuno possa aggiornarlo per favore? Non sembra funzionare in Python 3 come mostra type 'map' has no len(). Vorrei solo cambiare la seconda riga in iis=list(map(int,str(ii))). E qualcuno potrebbe spiegare la if i == 0: return iilinea per favore? Perché dovrebbe funzionare con input come 111 o 531? Grazie.
Bowen Liu,

L'ho corretto per Python 3 ora aggiungendo ´list () a iis = ... ´. I casi 111 e 531 non hanno soluzione ma la mia implementazione restituisce 111 e 531 per quelli. Potresti cambiarlo in un'eccezione di ciò che trovi meglio cambiando quella i == 0 riga.
Johan Lundberg,

Grazie. In realtà ho fatto un giro nell'altra direzione, quindi sono stato confuso da i == 0, mentre nella mia situazione lo sarà i == len(iis).
Bowen Liu,

8

Come minimo, ecco un paio di esempi di soluzioni basate su stringhe a forza bruta, che avresti dovuto essere in grado di escogitare dalla parte superiore della testa:

l'elenco delle cifre in 38276ordine è23678

l'elenco delle cifre in 38627ordine è23678

incremento della forza bruta, ordinamento e confronto

Lungo la forza bruta le soluzioni verrebbero convertite in una stringa e la forza bruta tutti i possibili numeri usando quelle cifre.

Crea da tutti questi elementi, inseriscili in un elenco e ordinali, ottieni la voce successiva dopo quella di destinazione.

Se avessi speso 30 minuti su questo e non avessi almeno un approccio alla forza bruta, non ti assumerei neanche io.

Nel mondo degli affari, una soluzione non elegante, lenta e goffa ma che fa il lavoro è sempre più preziosa di nessuna soluzione, infatti descrive praticamente tutti i software aziendali, ineleganti, lenti e goffi.


1
Bene, il mio primo commento fuori dal pipistrello è stato "Potrei forzarlo brutalmente ma ...". Se davvero non esiste una soluzione algoritmica, sono un po 'deluso
bhan,

4
Se fossi l'intervistatore, non sarei così felice con un approccio di forza bruta.
Ahmad Y. Saleh,

@benjamin han, esiste una soluzione algoritmica. Continua a scambiare le cifre iniziando da destra, fino a trovare il risultato. Non è necessario calcolare tutti i permutatnios prima.
dantuch,

7
Esistono sicuramente soluzioni migliori della forza bruta, ad esempio ardendertat.com/2012/01/02/…
BrokenGlass,

@BrokenGlass Sicuramente una soluzione molto migliore. Avevo appena avuto l'idea e poi hai pubblicato l'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;
}

Ho trovato questa soluzione. Per favore, se avete qualche domanda, chiedete.
Ashikodi,

4

La tua idea

Volevo iniziare trovando l'indice della prima cifra (da destra) che era inferiore a quella. Quindi avrei ruotato le ultime cifre nel sottoinsieme in modo che fosse il numero più grande successivo composto dalle stesse cifre, ma mi sono bloccato.

è abbastanza buono, in realtà. Devi solo considerare non solo l'ultima cifra ma tutte le cifre di minor significato rispetto a quelle attualmente considerate. Da prima che si raggiunga, abbiamo una sequenza monotonica di cifre, che è la cifra più a destra più piccola del suo vicino destro. Considerare

1234675
    ^

Il prossimo numero più grande con le stesse cifre è

1234756

La cifra trovata viene scambiata con l'ultima cifra - la più piccola delle cifre considerate - e le cifre rimanenti sono disposte in ordine crescente.


4

Sono abbastanza sicuro che il tuo intervistatore stesse cercando di spingerti delicatamente verso qualcosa del genere:

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

Non necessariamente la soluzione più efficiente o elegante, ma risolve l'esempio fornito in due cicli e scambia le cifre una alla volta come ha suggerito.


2

Prendi un numero e dividilo in cifre. Quindi se abbiamo un numero di 5 cifre, abbiamo 5 cifre: abcde

Ora scambia d ed e confronta con il numero originale, se è più grande, hai la tua risposta.

Se non è più grande, scambia e e c. Ora confronta e se è più piccolo scambia d ed e di nuovo (nota la ricorsione), prendi il più piccolo.

Continua fino a trovare un numero maggiore. Con la ricorsione dovrebbe funzionare come circa 9 linee di schema o 20 di c #.


2

Questa è una domanda molto interessante.

Ecco la mia versione java. Mi ci vogliono circa 3 ore per capire il modello per completare completamente il codice prima di controllare i commenti degli altri partecipanti. Sono contento di vedere che la mia idea è abbastanza simile con gli altri.

O (n) soluzione. Onestamente, fallirò questa intervista se il tempo è di soli 15 minuti e richiedo la fine del codice completo sulla lavagna.

Ecco alcuni punti interessanti per la mia soluzione:

  • Evitare qualsiasi ordinamento.
  • Evitare completamente il funzionamento delle stringhe
  • Ottieni complessità spaziale O (logN)

Ho inserito un commento dettagliato nel mio codice e il Big O in ogni passaggio.

  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;

}

Ecco il risultato in esecuzione in Intellj:

959879532-->959892357
1358642-->1362458
1234567-->1234576
77654321-->77654321
38276-->38627
47-->74

nel caso 123 quale sarà la risposta? Praticamente il codice non genererà output mentre verrà generato 132
Dhaval dave

2

Un'implementazione javascript dell'algoritmo di @ 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;
};

1

Una soluzione (in Java) potrebbe essere la seguente (sono sicuro che gli amici qui possono trovare di meglio):
Inizia a scambiare le cifre dalla fine della stringa fino a quando non ottieni un numero più alto.
Vale a dire prima iniziare a spostare verso l'alto la cifra più bassa, quindi la successiva più alta ecc. Fino a quando non si colpisce la successiva più alta.
Quindi ordina il resto. Nel tuo esempio otterrai:

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

@yi_H: l'output è 63872.Perché, quale dovrebbe essere?
Cratylus,

bene .. prossimo numero più alto? :) questo era il requisito, no?
Karoly Horvath,

@BlueRaja - Danny Pflughoeft: Grazie per il tuo aiuto. Ho cambiato il codice come segue: sposta la prima cifra in anticipo (che produce sempre un numero più alto) e ordina il resto
Cratylus,

1

Se stai programmando in C ++, puoi usare 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;
}

Cosa succede se inserisco 100? :-)
jweyrich,

1

Non sapevo nulla dell'algoritmo della forza bruta quando rispondevo a questa domanda, quindi mi sono avvicinato da un'altra angolazione. Ho deciso di cercare l'intera gamma di possibili soluzioni in cui questo numero potrebbe essere riorganizzato, a partire da number_given + 1 fino al numero massimo disponibile (999 per un numero a 3 cifre, 9999 per 4 cifre, ecc.). Ho fatto questo tipo di trovare un palindromo con le parole, ordinando i numeri di ciascuna soluzione e confrontandolo con il numero ordinato indicato come parametro. Ho quindi semplicemente restituito la prima soluzione nella gamma di soluzioni, poiché questo sarebbe il prossimo valore possibile.

Ecco il mio codice in 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

qual è la complessità temporale di questa soluzione?
Nitish Upreti,

@ Myth17 Non ne sono sicuro, dato che non l'ho mai provato. Se vuoi scoprirlo, dai un'occhiata a questo post: stackoverflow.com/questions/9958299/…
Jeremiah McCurdy,

1

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

0

L'ho provato solo con due numeri. Loro lavorarono. Come responsabile IT per 8 anni fino alla pensione dello scorso dicembre, mi sono preoccupato di tre cose: 1) Precisione: va bene se funziona - sempre. 2) Velocità: deve essere accettabile per l'utente. 3) Chiarezza: probabilmente non sono intelligente come te, ma ti pago. Assicurati di spiegare cosa stai facendo, in inglese.

Omar, buona fortuna per il 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


0

Ecco il mio codice, è una versione modificata di questo esempio

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

Test:

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

    int b = NumPermExample.nextPermutation(a);

    System.out.println("a: "+a+", b: "+b);
}

0

Aggiungi 9 al numero indicato di n cifre. Quindi controlla se rientra nel limite (il primo numero di cifre (n + 1)). In tal caso, verificare se le cifre nel nuovo numero sono uguali a quelle nel numero originale. Ripetere l'aggiunta di 9 fino a quando entrambe le condizioni sono vere. Ferma l'algo quando il numero supera il limite.

Non sono riuscito a trovare un caso di prova contraddittorio per questo metodo.


1
Funziona, ma estremamente lentamente. È un algoritmo di tempo esponenziale in cui questo potrebbe essere risolto in tempo lineare.
interjay

0

Solo un'altra soluzione che usa 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)

Produzione:

23541

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

    }

0

Di seguito è riportato il codice per generare tutte le permutazioni di un numero .. anche se uno deve convertire quel numero intero in stringa usando prima String.valueOf (intero).

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

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

0

Ennesima implementazione Java, eseguibile immediatamente e completata con test. Questa soluzione è O (n) spazio e tempo usando una buona vecchia programmazione dinamica.

Se uno vuole bruteforce, ci sono 2 tipi di bruteforce:

  1. Permetti tutte le cose, quindi scegli min più in alto: O (n!)

  2. Simile a questa implementazione, ma invece di DP, l'esecuzione forzata della fase di popolamento della mappa indexToIndexOfNextSmallerLeft verrà eseguita in 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);
    }

}

0

Dobbiamo trovare il bit 0 più a destra seguito da un 1 e capovolgere questo bit da 0 a 1.

per esempio diciamo che il nostro input è 487, che è 111100111 in binario.

capovolgiamo lo 0 più a destra con 1 seguito

quindi otteniamo 111101111

ma ora abbiamo 1 in più e uno in meno di 0, quindi riduciamo il numero di 1 a destra del flip bit di 1 e aumentiamo il no di 0 bit di 1, ottenendo

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

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

0

Ecco l'implementazione 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;
}

Ecco i test unitari

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

0

So che questa è una domanda molto vecchia ma ancora non ho trovato il codice facile in c #. Questo potrebbe aiutare i ragazzi che partecipano alle interviste.

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

0

Implementazione molto semplice usando Javascript, il prossimo numero più alto con le stesse cifre

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

Dato che ci sono molti commenti, quindi è meglio che tu possa copiarlo nel tuo editor di testo. Grazie!


0

Ci sono molte buone risposte ma non ho trovato un'implementazione Java decente. Ecco i miei due centesimi:

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

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;
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.