Chỉ số hoán vị nghịch đảo


17

Giới thiệu

Các hoán vị từ vựng của một danh sách với n phần tử có thể được đánh số từ 0 đến n ! - 1. Ví dụ: 3! = 6 hoán vị của (1,2,3)sẽ (1,2,3), (1,3,2), (2,1,3), (2,3,1), (3,1,2), (3,2,1).

Khi một hoán vị được áp dụng cho một danh sách, các phần tử của nó được sắp xếp theo thứ tự giống như các số trong hoán vị. Ví dụ, áp dụng hoán vị (2,3,1)cho l = (a,b,c)năng suất (l[2],l[3],l[1]) = (b,c,a).

Nghịch đảo của một hoán vị được định nghĩa là hoán vị đảo ngược hoạt động này, tức là áp dụng một hoán vị và sau đó nghịch đảo của nó (hoặc ngược lại) không sửa đổi mảng. Ví dụ, nghịch đảo (2,3,1)(3,1,2), kể từ khi áp dụng điều đó vào (b,c,a)năng suất (a,b,c).

Ngoài ra, nghịch đảo của hoán vị áp dụng cho các hoán vị riêng của mình mang lại các số nguyên từ 1 ... n . Ví dụ, áp dụng (3,1,2)cho (2,3,1)năng suất (1,2,3).

Bây giờ chúng ta định nghĩa hàm revind ( x ) là chỉ số của hoán vị nghịch đảo của hoán vị với chỉ số x . (Đây là A056019 , nếu bạn quan tâm.)

Vì hoán vị với chỉ mục i chỉ sửa đổi các mục k cuối cùng của danh sách iff 0 ≤ i < k !, Nên chúng tôi có thể thêm bất kỳ số phần tử nào vào đầu danh sách mà không ảnh hưởng đến revind ( i ). Do đó độ dài của danh sách không ảnh hưởng đến kết quả.

Thử thách

Nhiệm vụ của bạn là thực hiện revind ( x ). Bạn sẽ viết một chương trình hoặc hàm đầy đủ có một số nguyên không âm x là đầu vào / đối số và xuất / trả về kết quả dưới dạng một số nguyên không âm.

Đầu vào và đầu ra có thể là 0-index hoặc 1-index, nhưng điều này phải nhất quán giữa chúng.

Các nội trang tạo ra hoán vị theo chỉ mục, trả về chỉ mục của hoán vị hoặc tìm hoán vị nghịch đảo đều bị cấm. (Được phép tạo ra tất cả các hoán vị hoặc hoán vị tiếp theo.)

Luật tiêu chuẩn được áp dụng.

Ví dụ

Các ví dụ dưới đây được lập chỉ mục 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

Tham chiếu thực hiện (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
Tôi đã phải tìm định nghĩa của hoán vị nghịch đảo để hiểu thách thức này. Tôi tìm thấy ví dụ của bạn với (a,b,c)cực kỳ không rõ ràng. Vui lòng bao gồm một lời giải thích thích hợp về hoán vị nghịch đảo là gì.
Gây tử vong

@Firthize Điều này thật khó để giải thích một cách đơn giản. Tốt hơn rồi?
PurkkaKoodari

Jelly có nguyên tử (tăng cấp) sắp xếp các chỉ số của một mảng theo các giá trị tương ứng của chúng. Điều này xảy ra để đảo ngược một hoán vị 1, Mạnh, n , nhưng nó không hoạt động cho các hoán vị khác. Là một cấm tích hợp?
Dennis

@Dennis Câu hỏi khó. Về mặt kỹ thuật, nó tìm thấy nghịch đảo của bất kỳ hoán vị nào sau khi nó được áp dụng cho bất kỳ danh sách tăng nghiêm ngặt nào. Vì vậy tôi sẽ nói không được phép. (Nếu ai đó hoàn toàn không đồng ý, vui lòng bình luận. Tôi có thể thay đổi điều này nếu cộng đồng mong muốn.)
PurkkaKoodari

Câu trả lời:


5

Thạch , 6 byte

ịŒ!⁺iR

I / O sử dụng lập chỉ mục dựa trên 1. Rất chậm và đói bộ nhớ.

xác minh

Miễn là đầu vào không vượt quá 8! = 40320 , đủ để xem xét tất cả các hoán vị của mảng [1, Rèn, 8] . Đối với trường hợp thử nghiệm cuối cùng, hoán vị của [1, Mạnh, 9] là đủ.

Với mã được sửa đổi một chút chỉ xem xét hoán vị của 8 hoặc 9 số nguyên dương đầu tiên , bạn có thể dùng thử trực tuyến!hoặc xác minh tất cả các trường hợp thử nghiệm còn lại .

Làm thế nào nó hoạt động

ịŒ!⁺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.

Cách tiếp cận thay thế, 6 byte (không hợp lệ)

Œ!Ụ€Ụi

Nó chỉ dài và nó sử dụng bị cấm nguyên tử lên cấp , nhưng nó (có thể nói là) thành ngữ hơn.

Bằng cách trả trước 8 (hoặc 9 cho trường hợp thử nghiệm cuối cùng), chúng tôi thực sự có thể Dùng thử trực tuyến!

Làm thế nào nó hoạt động

Œ!Ụ€Ụ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

Toán học, 74 byte

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

Sử dụng 1 chỉ mục. Rất kém hiệu quả. (sử dụng ~ 11GB bộ nhớ khi đầu vào là 11)

Giải trình

j=Range@#

Tạo một danh sách từ 1 đến N. Lưu trữ trong đó j.

i=Permutations[...]

Tìm tất cả các hoán vị của j. Lưu trữ mà trong i.

k=Position

Lưu trữ Positionchức năng trong k. (để giảm số byte khi sử dụng Positionlại)

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

Tìm hoán vị nghịch đảo của hoán vị N-th.

Max@k[i,...]

Tìm k( Position) của hoán vị nghịch đảo trong i(tất cả các hoán vị)

Sử dụng tích hợp, 46 43 byte

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

1 chỉ mục.


2
"Các công cụ xây dựng ... tìm hoán vị nghịch đảo bị cấm"
Greg Martin

@GregMartin, ah, bằng cách nào đó tôi đã bỏ lỡ phần đó và chỉ thấy phần "trả về chỉ số của một hoán vị". Ngớ ngẩn với tôi ... Mã mới không có vấn đề đó.
JungHwan Min

vâng, tôi đồng ý nó rất dễ bỏ lỡ. 74 byte vẫn còn khá ấn tượng!
Greg Martin

5

MATL , 15 byte

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

Đầu vào và đầu ra là 1 dựa trên.

Tương tự như câu trả lời CJam của @ MartinEnder , nhưng tìm thấy hoán vị nghịch đảo bằng cách kết hợp tất cả các hoán vị có thể có với chỉ định của đầu vào và xem cái nào đã trở thành hoán vị nhận dạng.

Nó hết bộ nhớ trong trình biên dịch trực tuyến cho đầu vào 10.

Hãy thử trực tuyến!

Giải trình

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

Bình thường, 12 byte

xJ.phQxL@JQh

Bộ kiểm tra

0 được lập chỉ mục.

Giải trình:

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 byte

Bộ nhớ rất kém hiệu quả. Bây giờ thậm chí nhiều bộ nhớ không hiệu quả (nhưng ngắn hơn 1 byte).
Phạm vi dựa trên 0.
Sử dụng mã hóa CP-1252 .

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

Hãy thử trực tuyến! hoặc như một bộ kiểm tra sửa đổi

Giải trình

ƒ               # 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 byte

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

Các chỉ số dựa trên 0.

Hãy thử trực tuyến!

Tôi không nhận được nhiều hiệu quả hơn thế này ... hết bộ nhớ với các cài đặt mặc định của Java cho các đầu vào lớn hơn 8 (nhưng về nguyên tắc hoạt động cho các đầu vào tùy ý được cung cấp đủ số lượng thời gian và bộ nhớ).

Giải trình

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 byte

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

1 chỉ mục. Dòng mới không được tính, chúng không cần thiết. Tôi thực sự không phải gán chức năng cuối cùng cho một cái tên, nhưng ...

hlà một hàm được xử lý lấy một danh sách các hoán vị và một chỉ mục vào danh sách đó và trả về chỉ số của hoán vị nghịch đảo. Không có giới hạn, tôi chỉ cần làm Position(l,l[n]^-1).fgọi hàm đó với các hoán vị được sắp xếp của một nhóm đối xứng đủ lớn và nhóm đã chon .

Tôi chỉ có thể viết SymmetricGroup(n), sau đó hàm có thể được tính cho các giá trị lên đến 9. Vì đã có các giải pháp nhỏ hơn nhiều, tôi thích có thể làm điều này:

gap> f(100001);
303017

Một giải pháp 0 chỉ mục thực sự hiệu quả, hoạt động cho các đối số dưới 99! (và có thể được thực hiện để hoạt động cho các đối số dưới 999! với chi phí là một byte) là cái này:

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;

Sau khi xóa khoảng trắng, cái này có 255 byte.


Công việc tốt đẹp! Tôi hy vọng sẽ có được một số giải pháp hiệu quả quá.
PurkkaKoodari

3

JavaScript (ES6), 163 120 110 byte

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>

Chỉ số 0. Hoạt động bằng cách chuyển đổi chỉ mục thành hoán vị, đảo ngược nó, sau đó chuyển đổi trở lại thành một chỉ mục. Chỉnh sửa: Đã lưu khoảng 25% bằng cách thực hiện fđảo ngược và đảo ngược hoán vị, sau đó thực hiện gchuyển đổi hoán vị đảo ngược trở lại một chỉ mục. Đã lưu thêm 10 byte bằng cách kết hợp hai cuộc gọi đệ quy thành một hàm duy nhất. Ung dung:

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
@Jonathan ALLan Xin lỗi, tôi nghĩ rằng tôi đã phát hiện ra việc tiết kiệm 9 byte giây cuối cùng nhưng tôi đã không kiểm tra kỹ lưỡng. Tôi đã trở lại phiên bản trước của tôi.
Neil

Thực hiện rất swish bây giờ.
Jonathan Allan

1
@Jonathan ALLan Hóa ra thậm chí còn hay ho hơn nếu tôi fđảo ngược hoán vị thay vì g...
Neil

3

J, 55 50 byte

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

Dựa trên bài luận J về Chỉ số hoán vị .

Mã này chỉ yêu cầu bộ nhớ theo thứ tự nnhưng sử dụng nhiều thời gian hơn vì nó sắp xếp nthời gian danh sách và tìm kiếm nón lần cho mỗi chỉ mục.

Sử dụng nội dung /:có thể tìm thấy cấp của danh sách và nghịch đảo của hoán vị, có một giải pháp 42 byte hiệu quả hơn.

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

Phiên bản này chỉ cần 44 giây để tính toán trường hợp thử nghiệm cuối cùng khi so sánh với phiên bản khác cần 105 giây.

Sử dụng

   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 cho hiệu quả bộ nhớ mà các ngôn ngữ chơi gôn không thể chạm tới.
Bạch tuộc ma thuật Urn

2

Thạch , 14 13 9 byte

-4 byte nhờ vào @Dennis (anh ấy đã đánh gôn thêm bằng cách sử dụng nhanh trong câu trả lời của mình )

Œ!ịịŒ!$iR

Một cách thực hiện rất chậm.
Lập chỉ mục dựa trên 1 được sử dụng ở đây, vì vậy kết quả mong đợi là:

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

Thậm chí không có điểm nào trong việc đưa ra một liên kết IDE trực tuyến, vì TIO giết chết đầu vào của 10. Kết quả cục bộ (cuối cùng rất chậm và cần một tấn bộ nhớ!):

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

Làm sao?

Œ!ịịŒ!$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]

Lưu ý: không cần sắp xếp các hoán vị vì chúng ta đang sử dụng cùng một thứ tự cho cả việc tìm hoán vị và nghịch đảo.


Không thể kiểm tra nó từ điện thoại của tôi, nhưng bạn không thể thoát khỏi liên kết 2 và tạo liên kết chính ÇịịÇ$iR?
Dennis

Thật ra, Rtrước đây Œ!là ngầm, Œ!ịịŒ!$iRnên làm việc.
Dennis

Vâng, đây là một mục rất vội vàng trước khi gặp gỡ bạn bè.
Jonathan Allan

2

Python 2, 116 114 byte

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

thay thế

Dựa trên 0 Chậm và bộ nhớ đói nhưng ngắn trên byte.


Sử dụng không có chức năng hoán vị; cả bộ nhớ và thời gian hiệu quả. 289 285 byte

-4 byte nhờ vào @Christian Sievers (hoán vị đầy đủ đã được hình thành)

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

Tôi biết đó là mã golf nhưng tôi nghĩ @ Pietu1998 cũng quan tâm đến việc triển khai hiệu quả.

Xem nó trong hành động tại repl.it

Trong khi điều này sử dụng nhiều byte hơn so với triển khai tham chiếu so sánh cho n=5000000:

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

f là hàm chỉ số ngược.

fđầu tiên nhận được thừa kế ở trên n, tvà số nguyên mà thừa có nghĩa là, xbằng cách gọi điện thoạih(n) , và bộ g=range(x), các mục mà sẽ tạo nên hoán vị,o=g[:] và người giữ hoán vị,r=[]

Tiếp theo, nó xây dựng hoán vị tại chỉ mục nbằng cách poplấy các chỉ mục của biểu diễn cơ sở giai thừa nlần lượt từ các mục ovà nối chúng vào r. Các đại diện cơ sở thừa được tìm thấy bởi div và mod của nvới tnơit div'd bởi xx decrements xuống 1.

Cuối cùng, nó tìm thấy chỉ số của hoán vị ngược bằng cách gọi i với hoán vị ngược,[r.index(v)for v in g]

h là một hàm mục đích kép để tính giai thừa của một số nguyên không âm hoặc tính cả hai giai thừa tiếp theo trên một số nguyên không âm và số nguyên tạo ra giai thừa đó.

Ở trạng thái mặc định của nó v=1và nó thực hiện sau bằng cách nhân vvới x(cũng ban đầu 1) và tăng dần xcho đến khi nít nhất là lớn, sau đó nó trả về vx-1trong một tuple.

Để tính toán n!một cuộc gọi h(n,0)mà bội x(ban đầu 1) bằng nvà suất này ncho đến khi n0khi nó trả về x.

icung cấp chỉ số từ vựng của một hoán vị, pcủa các mục [0,1,...n]bằng cách thêm các sản phẩm của giai thừa của cơ sở giai thừa của mỗi chỉ số h(len(p)-j-1,0)và có bao nhiêu mục ở bên phải của chỉ mục nhỏ hơn giá trị tại chỉ mục đó sum(k<p[j]for k in p[j+1:]).


Tôi nghĩ bạn không cần phải đặc biệt trường hợp cuối cùng khi xây dựng hoán vị. Tôi đã không có trong giải pháp GAP 255 byte của mình.
Christian Sievers

Tôi thêm nó một cách riêng biệt vào cuối bởi vì nếu không sẽ có một lỗi chia cho số 0 khi nó xảy ra t/=x.
Jonathan Allan

Mất một lúc để xem: vòng lặp đã làm tất cả, bạn có thể thay thế (r+o)bằng r.
Christian Sievers

Uh, bạn nói đúng! Cảm ơn bạn rất nhiều.
Jonathan Allan

1

Python 2, 130 129 byte

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

Thật ra , 18 11 byte

Câu trả lời này sử dụng thuật toán trong câu trả lời Jelly của Dennis nhưng được lập chỉ mục 0. Gợi ý chơi golf chào mừng! Hãy thử trực tuyến!

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.
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.