Індекс зворотної перестановки


17

Вступ

Лексикографічні перестановки списку з п елементами можуть бути пронумеровані від 0 до n ! - 1. Наприклад, 3! = 6 перестановок (1,2,3)буде (1,2,3), (1,3,2), (2,1,3), (2,3,1), (3,1,2), (3,2,1).

Коли перестановка застосована до списку, її елементи упорядковуються в тому ж порядку, що і числа в перестановці. Наприклад, застосування перестановки (2,3,1)до l = (a,b,c)врожайності (l[2],l[3],l[1]) = (b,c,a).

Зворотна перестановка визначається як перестановка, яка обертає цю операцію, тобто застосовуючи перестановку, а потім її зворотна (або навпаки) не змінює масив. Наприклад, зворотне значення (2,3,1)є (3,1,2), оскільки застосовується це до (b,c,a)врожайності (a,b,c).

Крім того, зворотна перестановка, застосована до самої перестановки, дає цілі числа 1… n . Наприклад, звернення (3,1,2)до (2,3,1)врожайності (1,2,3).

Тепер ми визначимо функцію revind ( x ) як індекс зворотної перестановки перестановки з індексом x . (Це A056019 , якщо вам це цікаво.)

Оскільки перестановка з індексом i змінює лише останні k елементи списку iff 0 ≤ i < k !, Ми можемо додати будь-яку кількість елементів до початку списку, не впливаючи на revind ( i ). Тому довжина списку не впливає на результат.

Виклик

Ваше завдання - реалізувати перемотування ( x ). Ви напишете повну програму або функцію, яка приймає одне негативне ціле число x як вхід / аргумент та виводить / повертає результат у вигляді одного невід’ємного цілого числа.

Вхід і вихід можуть бути 0-індексованими або 1-індексованими, але це повинно бути узгоджено між ними.

Вбудовані, які генерують перестановки за індексом, повертають індекс перестановки або знаходять зворотну перестановку, заборонені. (Вбудовані, які генерують усі перестановки або наступну перестановку, дозволені.)

Стандартний правила .

Приклади

Наведені нижче приклади є 0-індексованими.

Input    Output
0        0
1        1
2        2
3        4
4        3
5        5
6        6
13       10
42       51
100      41
1000     3628
2000     3974
10000    30593
100000   303016

Реалізація посилань (Python 3)

def revind(n):
    from math import factorial
    from itertools import permutations, count
    l = next(filter(lambda x: factorial(x) > n, count(1)))
    pms = list(permutations(range(l)))
    return [k for k in range(len(pms)) if tuple(pms[n][i] for i in pms[k]) == pms[0]][0]


1
Мені довелося шукати визначення зворотної перестановки, щоб зрозуміти цю проблему. Я вважаю ваш приклад (a,b,c)вкрай незрозумілим. Будь ласка, додайте належне пояснення, що таке обернена перестановка.
Фаталізувати

@Fatalize Це щось важко пояснити просто. Краще зараз?
PurkkaKoodari

Jelly має атом (grade up), який сортує індекси масиву за відповідними значеннями. Це трапляється для перетворення перестановки 1,…, n , але це не працює для інших перестановок. Чи заборонений вбудований?
Денніс

@Денніс Важке запитання. Технічно він виявляє зворотну сторону будь-якої перестановки після її застосування до будь-якого суворо зростаючого списку. Тому я хочу сказати, що це не дозволено. (Якщо хтось категорично не погоджується,
сміливо

Відповіді:


5

Желе , 6 байт

ịŒ!⁺iR

Введення / виведення використовує індексацію на основі 1. Дуже повільний і голодний на пам'ять.

Перевірка

Поки вхід не перевищує 8! = 40320 , достатньо розглянути всі перестановки масиву [1,…, 8] . Для останнього тестового випадку перестановки [1,…, 9] достатньо .

Злегка модифікований код, який враховує лише перестановки перших 8 чи 9 натуральних чисел, ви можете спробувати його в Інтернеті! або перевірити всі залишки тесту .

Як це працює

ịŒ!⁺iR  Main link. Argument: n

 Œ!     Yield all permutations of [1, ..., n].
ị       At-index; retrieve the n-th permutation.
   ⁺    Duplicate the Œ! atom, generating all permutations of the n-th permutation.
     R  Range; yield [1, ..., n].
    i   Index; find the index of [1, ..., n] in the generated 2D array.

Альтернативний підхід, 6 байт (недійсний)

Œ!Ụ€Ụi

Це так само довго, і він використовує заборонений атом сорту , але він (імовірно) більш ідіоматичний.

Попередньо 8 (або 9 для останнього тестового випадку) ми можемо фактично спробувати його в Інтернеті!

Як це працює

Œ!Ụ€Ụi  Main link. Argument: n

Œ!      Yield all permutations of [1, ..., n].
  Ụ€    Grade up each; sort the indices of each permutation by the corresponding
        values. For a permutation of [1, ..., n], this inverts the permutation.
    Ụ   Grade up; sort [1, ..., n!] by the corresponding inverted permutations
        (lexicographical order).
     i  Index; yield the 1-based index of n, which corresponds to the inverse of
        the n-th permutation.

6

Математика, 74 байти

Max@k[i,Flatten@Outer[i=Permutations[j=Range@#];k=Position,{i[[#]]},j,1]]&

Використовує 1-індексацію. Дуже неефективно. (при вході використовується ~ 11 Гб пам'яті 11)

Пояснення

j=Range@#

Створіть список від 1 до N. Магазин, що в j.

i=Permutations[...]

Знайти всі перестановки j. Зберігайте це в i.

k=Position

Збережіть Positionфункцію в k. (зменшити кількість байтів при Positionповторному використанні )

Flatten@Outer[...,{i[[#]]},j,1]

Знайдіть зворотну перестановку N-ї перестановки.

Max@k[i,...]

Знайти k(Position ) обернену перестановку в i(усі перестановки)

Використовуючи вбудовані, 46 43 байти

a[(a=Ordering)/@Permutations@Range@#][[#]]&

1-індексований.


2
"Вбудовані, які ... знаходять зворотну перестановку, заборонені",
Грег Мартін

@GregMartin, ах, я якось пропустив цю частину і побачив лише частину "повернути індекс перестановки". Дурний мене ... Новий код не має цієї проблеми.
JungHwan Min

так, я згоден, це було легко пропустити. 74 байти - все ще дуже вражає!
Грег Мартін

5

MATL , 15 байт

:Y@tGY)Z)G:=!Af

Вхід і вихід на основі 1.

Подібно до відповіді CJam @ MartinEnder , але він знаходить зворотну перестановку, склавши всі можливі перестановки з тією, що вказана вводом, і бачачи, яка стала перестановкою ідентичності.

У інтернет-компіляторі для введення не вистачає пам'яті 10.

Спробуйте в Інтернеті!

Пояснення

:      % Implicitly input N. Push range [1 2 ... N]
Y@     % Matrix witll all permutations of size N. Each permutation is a row
tGY)   % Duplicate. Get the N-th row
Z)     % Use that as a column index into the matrix of all permutations
G:=    % Compare each row with [1 2 ... N]
!Af    % Find index of the row that matches. Implicitly display

5

Pyth, 12 байт

xJ.phQxL@JQh

Тестовий набір

0 індексовано.

Пояснення:

xJ.phQxL@JQh
xJ.phQxL@JQhQ    Implicit variable introduction
                 Q = eval(input())
  .phQ           Form all permutations of range(Q+1), namely [0, 1, .. Q]
 J               Save to J.
        @JQ      Take the Qth element of J.
      xL   hQ    Map all elements of [0, 1, ..., Q] to their index in above
x                Find the index in J of the above.

5

05AB1E , 14 13 байт

Дуже неефективна пам'ять. Тепер ще більше неефективна пам'ять (але на 1 байт коротше).
Діапазон на основі 0.
Використовує кодування CP-1252 .

ƒ¹ÝœD¹èNkˆ}¯k

Спробуйте в Інтернеті! або як модифікований тестовий набір

Пояснення

ƒ               # for N in range[0 .. x]
 ¹ÝœD           # generate 2 copies of all permutations of range[0 .. x]
     ¹è         # get permutation at index x
       Nkˆ      # store index of N in that permutation in global list
         }      # end loop
          ¯k    # get index of global list (inverse) in list of permutations

4

CJam , 16 байт

ri_)e!_@=_$\f#a#

Індекси базуються на 0.

Спробуйте в Інтернеті!

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

Пояснення

ri    e# Read input and convert to integer N.
_)e!  e# Duplicate N, get all permutations of [0 1 ... N].
_@=   e# Duplicate permutations, get the Nth permutation.
_$    e# Duplicate and sort to get the sorted range [0 1 ... N].
\f#   e# For each of these values, get its index in the Nth permutation.
      e# This inverts the permutation.
a#    e# Find the index of this new permutation in the list of all permutations.

3

GAP , 108 байт

h:=l->n->PositionProperty(l,p->l[n]*p=());
f:=n->h(Set(SymmetricGroup(First([1..n],k->Factorial(k)>=n))))(n);

1-індексований. Нові рядки не враховуються, вони не потрібні. Мені не потрібно присвоювати остаточну функцію імені, але ...

hце крива функція, що містить список перестановок та індекс до цього списку та повертає індекс зворотної перестановки. Без обмежень я б просто зробивPosition(l,l[n]^-1) . fвиклики, які функціонують з відсортованими перестановками досить великої симетричної групи та заданимиn .

Я міг би просто написати SymmetricGroup(n), тоді функцію можна було б обчислити для значень до 9. Оскільки рішення вже набагато менші, я вважаю за краще зробити це:

gap> f(100001);
303017

Дійсно ефективне 0-індексоване рішення, яке працює для аргументів нижче 99! (і можна змусити працювати на аргументи нижче 999! ціною одного байта) це:

f:=function(n)
 local m,l,p,i,g;
 m:=First([1..99],k->Factorial(k)>n);
 g:=List([m-1,m-2..0],Factorial);
 l:=[1..m];
 p:=[];
 for i in g do
  Add(p,Remove(l,QuoInt(n,i)+1));
  n:=n mod i;
 od;
 return Sum(ListN(List([1..m],i->Number([1..Position(p,i)],j->p[j]>i)),g,\*));
end;

Після видалення пробілів це має 255 байт.


Хороша робота! Я також сподівався отримати якісь ефективні рішення.
PurkkaKoodari

3

JavaScript (ES6), 163 120 110 байт

f=(n,a=[],i=0,r=0,[j,...b]=a)=>n?a.splice(n%-~i,0,i)|f(n/++i|0,a,i):i?f(n,b,i-1,b.reduce((r,k)=>r+=k>j,r*i)):r
<input type=number min=0 oninput=o.textContent=f(+this.value)><pre id=o>

0-індексований. Працює, перетворюючи індекс у перестановку, інвертуючи його, потім перетворюючи назад в індекс. Редагування: Збережено близько 25% за допомогою перетворення fта повернення перестановки, а потім gперетворення перевернутої перестановки назад в індекс. Збережено ще 10 байт, об’єднавши два рекурсивні виклики в одну функцію. Безголівки:

function index(n) {
    var a = [0];
    for (var i = 1; n = Math.floor(n / i); i++) {
        var j = i - n % (i + 1);
        for (var k = 0; k < i; k++) {
            if (a[k] > j) a[k]++;
        }
        a.push(j);
    }
    a = [...a.keys()].map(k => a.indexOf(k));
    while (i) {
        n *= i--;
        j = a.pop();
        for (k = 0; k < i; k++) {
            if (a[k] > j) n++;
        }
    }
    return n;
}

1
@JonathanAllan Вибачте, я думав, що помітив 9-байтну економію в останню секунду, але не зміг її ретельно перевірити. Я повернувся до попередньої версії.
Ніл

Зараз дуже швейцарська реалізація.
Джонатан Аллан

1
@JonathanAllan Виходить ще більш шумним, якщо мені вдасться fперевернути перестановку замість g...
Ніл

3

J, 55 50 байт

g=:/:~i.@#
[:(#\.#.+/@(<{.)\.)@g(-i.)@>:g@g@,/@#:]

За матеріалами J-реферату від індекс перестановки .

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

Використовуючи вбудований, /:який здатний знайти ступінь списку та зворотну перестановку, є 42-байтне рішення, яке є більш ефективним.

[:(#\.#.+/@(<{.)\.)@/:(-i.)@>:/:@/:@,/@#:]

Ця версія вимагає лише 44 секунди для обчислення останнього тестового випадку в порівнянні з іншим, який вимагає 105 секунд.

Використання

   g =: /:~i.@#
   f =: [:(#\.#.+/@(<{.)\.)@g(-i.)@>:g@g@,/@#:]
   (,.f"0) 0 1 2 3 4 5 6 13 42 100 1000 2000 10000
    0     0
    1     1
    2     2
    3     4
    4     3
    5     5
    6     6
   13    10
   42    51
  100    41
 1000  3628
 2000  3974
10000 30593
   timex 'r =: f 100000'
105.787
   r
303016

+1 за ефективність пам’яті, яку мови для гольфу не можуть торкнутися.
Чарівна Восьминіжка Урна

2

Желе , 14 13 9 байт

-4 байти завдяки @Dennis (який він надалі гольфував, використовуючи швидку у своїй відповіді )

Œ!ịịŒ!$iR

Ще одна дуже повільна реалізація.
Тут застосовується 1-базова індексація, тому очікувані результати:

input:  1 2 3 4 5 6 7 8  9 10 11
output: 1 2 3 5 4 6 7 8 13 19  9

Немає сенсу навіть встановлювати онлайн-посилання IDE, оскільки TIO вбиває на вході 10. Місцеві результати (останні дуже повільні і потребують тонни пам'яті!):

C:\Jelly\jelly-master>python jelly -fu D:\jelly_scripts\revPerm.txt 1
1
C:\Jelly\jelly-master>python jelly -fu D:\jelly_scripts\revPerm.txt 2
2
C:\Jelly\jelly-master>python jelly -fu D:\jelly_scripts\revPerm.txt 3
3
C:\Jelly\jelly-master>python jelly -fu D:\jelly_scripts\revPerm.txt 4
5
C:\Jelly\jelly-master>python jelly -fu D:\jelly_scripts\revPerm.txt 5
4
C:\Jelly\jelly-master>python jelly -fu D:\jelly_scripts\revPerm.txt 6
6
C:\Jelly\jelly-master>python jelly -fu D:\jelly_scripts\revPerm.txt 7
7
C:\Jelly\jelly-master>python jelly -fu D:\jelly_scripts\revPerm.txt 8
8
C:\Jelly\jelly-master>python jelly -fu D:\jelly_scripts\revPerm.txt 9
13
C:\Jelly\jelly-master>python jelly -fu D:\jelly_scripts\revPerm.txt 10
19
C:\Jelly\jelly-master>python jelly -fu D:\jelly_scripts\revPerm.txt 11
9

Як?

Œ!ịịŒ!$iR - Main link 1: n
      $   - last two links as a monad
    Œ!    -     permutations of implicit range [1,2,3,...,n]
   ị      -     value at index n (the nth permutation)
Œ!        - permutations of implicit range [1,2,3,...,n]
  ị       - value at index (the indexes of the permuted values in the nth permutation)
       i  - index of
        R - range [1,2,3,...,n]

Примітка: не потрібно сортувати перестановки, оскільки ми використовуємо однаковий порядок і для пошуку перестановки, і для зворотного.


Неможливо перевірити його з мого телефону, але ви не могли позбутися посилання 2 та зробити основне ÇịịÇ$iR?
Денніс

Власне, Rраніше Œ!це неявне, так і Œ!ịịŒ!$iRслід робити роботу.
Денніс

Так, це був дуже бурхливий запис перед зустріччю з друзями.
Джонатан Аллан

2

Python 2, 116 114 байт

from itertools import*
def f(n):r=range(n+1);l=list(permutations(r));print l.index(tuple(l[n].index(v)for v in r))

repl.it

На основі 0. Повільний і пам’ять голодний, але короткий на байтах.


Не використовуючи перестановочних функцій; як пам'ять, так і час. 289 285 байт

-4 байти завдяки @Christian Sievers (повна перестановка вже сформована)

h=lambda n,v=1,x=1:v and(n>=v and h(n,v*x,x+1)or(v,x-1))or n and h(n-1,0,n*x)or x
i=lambda p,j=0,r=0:j<len(p)and i(p,j+1,r+sum(k<p[j]for k in p[j+1:])*h(len(p)-j-1,0))or r
def f(n):t,x=h(n);g=range(x);o=g[:];r=[];exec"t/=x;x-=1;r+=[o.pop(n/t)];n%=t;"*x;return i([r.index(v)for v in g])

Я знаю, що це код гольфу, але я думаю, що @ Pietu1998 також зацікавлений у ефективній реалізації.

Дивіться це в дії на repl.it

Хоча для цього використовується більше байтів, ніж еталонна реалізація, порівнюючи n=5000000:

ref:    6GB 148s  
this: 200KB <1ms

f - це функція зворотного індексу.

fСпочатку отримує наступний факторіал вище n, tа також ціле число, чиє факторіальне значення є xза допомогою викликуh(n) та встановлення g=range(x), елементів, які становлять перестановку,o=g[:] , та власника перестановки,r=[]

Далі він будує перестановку в індексі nшляхом popіндексів факторного подання бази nпо черзі від елементів o, і додаючи їх до r. Факторне представлення базових знаходить діл і мод nз, tде tце поділеноx і xдекрементами до1 .

Нарешті він знаходить індекс зворотної перестановки шляхом виклику i зворотну перестановку,[r.index(v)for v in g]

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

У своєму стані за замовчуванням, v=1і він робить останнє, множуючи vна x(також спочатку 1) і збільшуючи, xпоки не nстане принаймні таким великим, тоді він повертається vіx-1 в кортежі.

Обчислити n!один виклик, h(n,0)який кратний x(спочатку 1) на nта зменшення nдо тих пір n, 0коли він повернеться x.

iзабезпечує лексикографічному індекс перестановки, p, деталі [0,1,...n]шляхом складання продуктів факторіала факторного підстави кожного індекс, h(len(p)-j-1,0)і скільки елементів праворуч від індексу менше , ніж значення в цьому індексі, sum(k<p[j]for k in p[j+1:]).


Я думаю, що вам не потрібно особливий регістр останнього елемента при побудові перестановки. Я не мав рішення з 255 байтів GAP.
Крістіан Сіверс

Я додаю його окремо наприкінці, тому що в іншому випадку буде ділення на нульову помилку, коли це станеться t/=x.
Джонатан Аллан

Мені потрібно було деякий час, щоб побачити: цикл вже робить все, що ви можете замінити (r+o)на r.
Крістіан Сіверс

А, ти маєш рацію! Дуже дякую.
Джонатан Аллан

1

Python 2, 130 129 байт

p=lambda x,k,j=1:x[j:]and p(x,k/j,j+1)+[x.pop(k%j)]
n=input();r=range(n+2);k=0
while[p(r*1,n)[i]for i in p(r*1,k)]>r:k+=1
print k

1

Власне , 18 11 байт

Ця відповідь використовує алгоритм у відповіді Денніса «Желе», але індексується 0. Пропозиції з гольфу вітаються! Спробуйте в Інтернеті!

4╞r;)╨E╨♂#í

Ungolfing

      Implicit input n.
4╞    Push 4 duplicates of n. Stack: n, n, n, n
r;)   Push the range [0...n], and move a duplicate of that range to BOS for later.
╨E    Push the n-length permutations of [0...n] and get perm_list[n].
        Stack: perm_list[n], n, [0...n]
╨     Push the n-length permutations of perm_list[n].
♂#    Convert every "list" in the zip to an actual list.
        Stack: perm(perm_list[n]), [0...n]
í     Get the index of [0...n] in the list of permutations of perm_list[n].
      Implicit return.
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.