Давши номер, знайдіть наступне вище число, яке має точно такий же набір цифр, що і вихідне число


226

Я просто бомбардував інтерв'ю і досягнув значного нульового прогресу в питанні свого інтерв'ю. Хтось може дозволити мені знати, як це зробити? Я спробував шукати в Інтернеті, але нічого не зміг знайти:

Давши номер, знайдіть наступне вище число, яке має точно такий же набір цифр, що і вихідне число. Наприклад: дано 38276 повернення 38627

Я хотів почати з пошуку індексу першої цифри (праворуч), який був меншим за число. Тоді я б обертав останні цифри в підмножині таким чином, щоб це було наступне найбільше число, що складається з тих же цифр, але застрягло.

Інтерв'юер також запропонував спробувати поміняти цифри по черзі, але я не зміг розібратися в алгоритмі і просто дивився на екран приблизно 20-30 хвилин. Потрібно говорити, що я думаю, що мені доведеться продовжувати пошуки роботи.

редагувати: для чого варто, мене запросили на наступний тур інтерв'ю


15
не задумуючись над цим занадто сильно, початок принаймні було б грубою силою обчислити всі перестановки цифр і захопити мінімальне число, яке перевищує вхідне число
BrokenGlass

13
в C ++ ви можете просто скористатися next_permutation;-)
thedayturns

9
FYI, ось як я вирішив це за 15 хвилин, ледве навіть думаючи про проблему: спочатку витратив 5 хвилин на написання алгоритму грубої сили, який просто створив усі можливі перестановки набору цифр, сортував їх і відобразив їх. Я провів 5 хвилин, переглядаючи ці дані, поки з переліку не з’явилася закономірність (тут прийняте рішення O (n) стало зрозумілим лише через короткий час), потім я витратив 5 хвилин на кодування алгоритму O (n).
Бен Лі

1
Взагалі, це не поганий спосіб розробити алгоритми для вирішення подібної проблеми, коли ви застрягли - використовуйте грубу силу на якомусь дрібному зразку, щоб створити багато даних, які потім зможете використовувати для легшого перегляду шаблонів.
Бен Лі

19
Я також хотів би зазначити, якщо ви дійсно не можете знайти ефективний спосіб зробити це, не роблячи нічого, це безпечний спосіб провалити співбесіду (а в діловому світі це вірний спосіб пропустити термін продукту) . Коли ви застрягли, замість того, щоб здаватись, вам слід було просто змусити це і викласти коментар вгорі "TODO: рефактор для продуктивності" або щось подібне. Якби я брав інтерв'ю, а хтось робив це, я б не обов'язково їх провалював. Принаймні, вони придумали щось, що працювало І визнали, що щось краще там, навіть якщо вони не змогли його знайти.
Бен Лі

Відповіді:


272

Ви можете зробити це O(n)(де nкількість цифр), як це:

Починаючи праворуч, ви знаходите перші пари цифр такими, що ліва цифра менша, ніж права. Звернімося до лівої цифри за допомогою "цифра-х". Знайдіть найменше число, що перевищує цифру-x, праворуч від цифри-х, і розмістіть її відразу ліворуч від цифри-х. Нарешті, сортуйте решта цифр у порядку зростання - оскільки вони вже були у порядку зменшення , все, що вам потрібно зробити, - це відмінити їх (зберегти для знаків-x, які можна розмістити в потрібному місці в O(n)) .

Приклад зробить це більш зрозумілим:

123456784987654321
Почніть з числа

123456784 987654321
         ^ перше місце справа, де ліва цифра менше правої  
         Цифра "х" дорівнює 4

123456784 987654321
              ^ знайдіть найменшу цифру більше 4 справа

123456785 4 98764321
        ^ розмістіть його зліва від 4

123456785 4 12346789
123456785123446789
         ^ сортуйте цифри праворуч від 5. Оскільки всі, крім 
         "4" вже були у порядку зменшення, все, що нам потрібно зробити 
         змінити їх порядок і знайти правильне місце для "4"

Доказ коректності:

Давайте використовувати великі літери для визначення цифр-рядків і малих літер для цифр. Синтаксис ABозначає "з'єднання рядків Aі B" . <- це лексикографічне впорядкування, яке є таким же, як ціле впорядкування, коли цифри-рядки мають однакову довжину.

Наше оригінальне число N має форму AxB, де xє одноцифрована і Bсортується за спаданням.
Число, знайдене нашим алгоритмом AyC, y ∈ B- це найменша цифра > x (воно повинно існувати у зв'язку із способом, який xбуло обрано, див. Вище) , і Cсортується за зростанням.

Припустимо, що є якесь число (з використанням одних і тих же цифр) N'таке AxB < N' < AyC. N'Починати треба з того, Aінакше він не може потрапити між ними, тому ми можемо записати це у формі AzD. Тепер наша нерівність є AxB < AzD < AyCрівнозначною тому, xB < zD < yCде всі три цифри-рядки містять однакові цифри.

Для того, щоб це було правдою, ми повинні мати x <= z <= y. Оскільки yнайменша цифра > x, zміж ними не може бути, тому z = xабо z = y. Скажи z = x. Тоді наша нерівність - xB < xD < yCце означає, B < Dде обидва Bі Dмають однакові цифри. Однак, В відсортоване по спадаючій, так що НЕ не рядки з цих цифр більше , ніж це. Таким чином, ми не можемо мати B < D. Виконуючи ті самі кроки, ми бачимо, що якщо цього z = yне можемо мати D < C.

Тому N'існувати не може, а це означає, що наш алгоритм правильно знаходить наступне найбільше число.


7
приємне рішення! є одне питання. скажіть, "найменша цифра більша за x" - y. чи можемо ми просто поміняти x і y, а потім повернути x.index + 1 -> end?
Кент,

8
Що відбувається з числом 99999?
Стерекс

19
@Sterex, це не просто 99999; будь-яке число, цифри якого вже повністю відсортовано у порядку зменшення, є максимальним (наприклад, 98765 також не має рішення). Це легко виявити програмно, тому що крок 1 алгоритму вийде з ладу (немає пари послідовних цифр, щоб "ліва цифра була меншою за праву цифру").
Бен Лі

3
@TMN: 9 більше, ніж 8, тож ви рухатиметеся 9 ліворуч від 8: 9 832потім сортуйте все праворуч від 9:9238
BlueRaja - Danny Pflughoeft

4
@Kent для вирішення роботи вам доведеться змінити знайти найменше цифра більше , ніж 4 , щоб право на знайти найменше цифра більше , ніж 4 від права . Інакше, наприклад, 1234567849876 55 4321 призведе до отримання 1234567851234 54 6789 (замість 1234567851234 45 6789). A nitpick :-)
osundblad

94

Майже ідентична проблема з'явилася як проблема Code Jam і тут є рішення:

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

Ось короткий опис методу на прикладі:

34722641

A. Розділіть послідовність цифр на дві частини, щоб права частина була якомога довшою, залишаючись у спадному порядку:

34722 641

(Якщо все число зменшується, більше великого числа не можна робити без додавання цифр.)

В.1. Виберіть останню цифру першої послідовності:

3472(2) 641

В.2. Знайдіть найменшу цифру у другій послідовності, яка більша за неї:

3472(2) 6(4)1

В.3. Поміняйте їх:

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

C. Сортуйте другу послідовність у порядку збільшення:

34724 126

D. Готово!

34724126

1
Друкарська помилка: я думаю "-> 34721 621" має бути "-> 34724 621"?
bjnord

1
@bjnord Хороший улов. Виправлено. Не впевнений, як мені це вдалося - це було правильно в наступних рядках.
Weeble

+1 Найкраща відповідь тут. Інтуїтивно зрозумілий і швидкий. (це також той, про який я думав, коли я це розробив на папері;))
Muhd

1
@Neel - На кроці C цифри, які ми хочемо сортувати, знаходяться у порядку зменшення, за винятком цифри, яку ми поміняли на кроці B. Щоб сортувати їх, нам насправді потрібно лише повернути їх назад і отримати поміщену цифру в потрібне положення. Саме так описує BlueRaja.
Weeble

1
@Dhavaldave У чому проблема? На кроці А ви отримуєте "12" і "3". На кроці B ви отримуєте "13" і "2". На кроці С нічого не змінюється. На кроці D ви отримуєте "132". Єдиний випадок, коли ви не отримаєте відповіді, це коли число вже є максимально можливим, наприклад, "321". У цьому випадку крок A дає "" і "321", і ви не можете продовжувати порожню послідовність для лівої частини розщеплення.
Weeble

14

Ось компактне (але частково жорстоке) рішення в Python

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

У C ++ ви можете зробити перестановки так: https://stackoverflow.com/a/9243091/1149664 (Це той самий алгоритм, що і в itertools)

Ось реалізація основної відповіді, описаної Weeble та BlueRaja, (інші відповіді). Я сумніваюся, що є щось краще.

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

Будь-який шанс, що хтось може оновити це, будь ласка? Схоже, це не працює в Python 3, як показано type 'map' has no len(). Я б просто змінив другий рядок на iis=list(map(int,str(ii))). І хтось може пояснити if i == 0: return iiрядок, будь ласка? Чому він би працював із введеннями, такими як 111 або 531? Дякую.
Боуен Лю

Я виправив це для python 3 зараз, додавши «list () до iis = ...». У випадках 111 і 531 немає рішення, але моя реалізація повертає 111 і 531 для цих питань. Ви можете змінити це на виняток, що краще, змінивши цей рядок i == 0.
Йохан Лундберг

Дякую. Я насправді петлю в інший бік, тому мене плутає i == 0, тоді як у моїй ситуації це буде i == len(iis).
Боуен Лю

8

Як мінімум, ось декілька прикладів грубих рішень на основі струнних рішень, які вам слід було б придумати прямо вгорі голови:

перелік цифр у 38276відсортованому вигляді23678

перелік цифр у 38627відсортованому вигляді23678

Збільшення грубої сили, сортування та порівняння

Разом з грубою силою рішення перетворюватимуться на String і brute force усі можливі числа за допомогою цих цифр.

Створіть з них всі вставки, покладіть їх у список і відсортуйте, отримайте наступний запис після цільового запису.

Якби ти витратив на це 30 хвилин і не придумав принаймні жорстокого підходу, я б і тебе не наймав.

У діловому світі рішення, яке є неелегантним, повільним і незграбним, але виконує роботу, завжди є більш цінним, ніж рішення взагалі не має. Фактично, що в значній мірі описує все програмне забезпечення бізнесу, неелегантне, повільне і незграбне.


1
Ну, моє перше зауваження від кажана було: "Я міг би грубо змусити це, але ...". Якщо насправді немає алгоритмічного рішення, я дуже розчарований
bhan

4
Якби я був інтерв'юером, я не був би такий задоволений грубим підходом.
Ахмад Ю. Салех

@benjamin han, існує алгоритмічне рішення. Просто продовжуйте міняти цифри, починаючи справа, поки не знайдете результат. Раніше не потрібно обчислювати всі permutatnios.
dantuch

7
Звичайно, є набагато кращі рішення, ніж груба сила, наприклад, ardendertat.com/2012/01/02/…
BrokenGlass

@BrokenGlass Безумовно, набагато краще рішення. Я щойно придумував цю ідею, а потім ви розмістили алгоритм.
Onit

5
function foo(num){
 sortOld = num.toString().split("").sort().join('');
 do{
    num++;
   sortNew = num.toString().split("").sort().join('');
 }while(sortNew!==sortOld);
 return num;
}

Я придумав таке рішення. Будь-ласка, якщо у вас виникли запитання.
Ашикоді

4

Ваша ідея

Я хотів почати з пошуку індексу першої цифри (праворуч), який був меншим за число. Тоді я б обертав останні цифри в підмножині таким чином, щоб це було наступне найбільше число, що складається з тих же цифр, але застрягло.

насправді гарно. Вам просто потрібно врахувати не тільки останню цифру, але й усі цифри, які мають меншу значимість, ніж розглянуті в даний час. Оскільки до цього не досягнуто, ми маємо монотонну послідовність цифр, тобто найправішу цифру, меншу, ніж її права сусідка. З повагою

1234675
    ^

Наступне більше число, що має однакові цифри, - це

1234756

Знайдена цифра обмінюється на останню цифру - найменшу з розглянутих цифр -, а решта цифр розташовуються у порядку зростання.


4

Я впевнений, що ваш інтерв'юер намагався вас обережно підштовхнути до чогось такого:

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

Не обов'язково найефективніше чи найелегантніше рішення, але воно вирішує поданий приклад у два цикли та замінює цифри один за одним, як він запропонував.


2

Візьміть число і розділіть його на цифри. Отже, якщо у нас є 5-значний номер, у нас є 5 цифр: abcde

Тепер поміняйте місцями d і e і порівняйте з початковим числом, якщо воно більше, ви маєте свою відповідь.

Якщо вона не більша, поміняйте місцями e і c. Тепер порівняйте, і якщо це буде менше swap d і e (помітити рекурсію), візьміть найменший.

Продовжуйте роботу, поки не знайдете більшу кількість. З рекурсією він повинен скласти приблизно 9 рядків схеми, або 20 c #.


2

Це дуже цікаве питання.

Ось моя версія Java. Займіть мене приблизно 3 години від з'ясування шаблону, щоб повністю закінчити код, перш ніж я перевірив коментарі інших учасників. Радий бачити, що моя ідея зовсім однакова з іншими.

O (n) розчин. Чесно кажучи, я не зможу цього інтерв'ю, якщо час буде лише 15 хвилин і вимагатиме повного закінчення коду на дошці.

Ось декілька цікавих моментів мого рішення:

  • Уникайте будь-якого сортування.
  • Уникайте поточної операції повністю
  • Досягнення O (logN) просторової складності

Я розміщую детальний коментар у своєму коді та Big O на кожному кроці.

  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;

}

Ось результат запуску в Intellj:

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

у випадку 123, що відповість? Практично ull-код не буде генерувати вихід, поки він не прийде 132
Дхаваль Дейв

2

Реалізація Javascript алгоритму @ 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

Рішенням (на Java) може бути наступне (я впевнений, що друзі тут можуть знайти краще):
Почніть міняти цифри з кінця рядка, поки не отримаєте більшу кількість.
Тобто спочатку почніть рух вгору за нижньою цифрою. Потім наступну вищу і т.д., поки не натиснете наступну вище.
Потім сортуйте решту. У вашому прикладі ви отримаєте:

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: Вихід є. 63872Чому це має бути?
Cratylus

ну .. наступне вище число? :) це була вимога, чи не так?
Каролі Горват

@BlueRaja - Danny Pflughoeft: Дякую за вашу допомогу. Я змінив код наступним чином: перемістіть найменшу цифру вперед (що коли-небудь дає більшу кількість) і відсортуйте решту
Cratylus

1

Якщо ви програмуєте на C ++, ви можете використовувати 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;
}

Що станеться, якщо я введіть 100? :-)
jweyrich

1

Я нічого не знав про алгоритм грубої сили, відповідаючи на це питання, тому підійшов до нього з іншого кута. Я вирішив пошукати весь спектр можливих рішень, в які це число можливо було б переставити, починаючи від числа_даних + 1 до максимального доступного числа (999 для 3-значний номер, 9999 для 4-х цифр тощо). Я зробив подібний варіант, як знайти паліндром зі словами, сортував числа кожного рішення і порівняв його з відсортованим числом, заданим як параметр. Потім я просто повернув перше рішення в масиві рішень, оскільки це було б наступне можливе значення.

Ось мій код у 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

яка часова складність цього рішення?
Nitish Upreti

@ Myth17 Я не впевнений, тому що ніколи цього не перевіряв. Якщо ви хочете розібратися в цьому, перегляньте цей пост: stackoverflow.com/questions/9958299/…
Jeremiah McCurdy

1

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

Я протестував це лише з двома номерами. Вони працювали. Як ІТ-менеджер протягом 8 років до виходу на пенсію минулого грудня, я дбав про три речі: 1) Точність: добре, якщо це працює - завжди. 2) Швидкість: повинна бути прийнятною для користувача. 3) Чіткість: я, мабуть, не такий розумний, як ви, але я вам плачу. Обов’язково поясніть, що ви робите, англійською мовою.

Омар, удача вперед.

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

Ось мій код, це модифікована версія цього прикладу

Бібліотека:

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

Тест:

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

    int b = NumPermExample.nextPermutation(a);

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

0

Додайте 9 до заданого n-цифрного числа. Потім перевірте, чи знаходиться воно в межах граничного (першого (n + 1) цифрного числа). Якщо це, то перевірте, чи цифри у новій кількості збігаються з цифрами у вихідному номері. Повторіть додавання 9, поки обидві умови не будуть виконані. Зупиніть альго, коли кількість виходить за межі.

Я не міг придумати суперечливий тестовий випадок цього методу.


1
Це працює, але надзвичайно повільно. Це експоненційний алгоритм часу, коли це можна було б вирішити за лінійний час.
interjay

0

Ще одне рішення за допомогою 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)

Вихід:

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

Нижче наведено код для генерації всіх перестановок числа .. хоча треба перетворити це ціле число в рядок, використовуючи спочатку String.valueOf (integer).

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

Ще одна реалізація Java, яку можна виконувати з коробки та завершувати тестами. Це рішення - O (n) простору та часу з використанням старого хорошого динамічного програмування.

Якщо ви хочете пограбувати, є два види грубої сили:

  1. Перестановіть усі речі, а потім виберіть мінімум вище: O (n!)

  2. Аналогічно цій реалізації, але замість DP, в O (n ^ 2) буде виконуватися грубе посилення кроку заповнення індексуToIndexOfNextSmallerLeft.


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

Нам потрібно знайти найбільш правильний біт 0, а потім 1 і перевернути цей правий найбільш 0 біт на 1.

наприклад, скажімо, що наш вхід становить 487, що становить 111100111 у двійковій формі.

ми перевертаємо праворуч найбільше 0, яке має 1 після нього

тому ми отримуємо 111101111

але тепер у нас є додатковий 1 і один менше 0, тому ми зменшуємо кількість 1 у правій частині біта фліп на 1 і збільшуємо число 0 біт на 1, отримуючи

111101011 - двійковий 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

Ось реалізація 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;
}

Ось одиничні тести

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

0

Я знаю, що це дуже давнє питання, але все-таки я не знайшов простий код у c #. Це може допомогти хлопцям, які відвідують співбесіди.

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

Дуже проста реалізація за допомогою Javascript, наступне найбільше число з однаковими цифрами

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

Оскільки коментарів дуже багато, тож краще скопіювати це у свій текстовий редактор. Дякую!


0

Є багато хороших відповідей, але я не знайшов гідної реалізації Java. Ось два мої центи:

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;
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.