順列のサイクル数


23

次のような整数の順列1、...、を考えてみましょう。nn = 6

[5,2,4,3,6,1]

順列をから[1,2,3,4,5,6]へのマッピングとして表示する場合[5,2,4,3,6,1]、順列は互いに素なサイクルに分解できます。サイクルは、相互にマッピングされる要素のサブセットです。たとえば、1にマッピングされます5。これはにマッピングされ6、にマッピングされ1ます。したがって、1サイクルは[1,5,6]です。他のサイクルがある[2][3,4]。したがって、この順列のサイクル数3です。

一般に、順列のサイクルは一意で(最大)、サイズの順列のサイクル数nはから1に変化しnます。

チャレンジ

空でない順列が与えられた場合、そのサイクル数を出力します。

入力によって形成された配列であるn整数12、...、nどこ、n > 0。各整数は1回だけ出現します。上記の例のように、それらが現れる順序は順列を定義します。

配列の代わりに、リスト、数字の間の区切り文字を持つ文字列、各数字の個別の入力、または妥当なものを使用できます。

サイズの順列でnは、1から始まる整数のセット1...の代わりにn、0から始まるセット0... を一貫して使用できますn-1。もしそうなら、あなたの答えでそれを示してください。

コードは、のために働く必要がありますnまで20、妥当な時間で1分未満を言います。

コードゴルフ。すべてのビルトインが許可されます。

テストケース

これは、1ベースの配列入力を前提としています。

 [1] -> 1
 [3,2,1] -> 2
 [2,3,4,5,1] -> 1
 [5,2,4,3,6,1] -> 3
 [8,6,4,5,2,1,7,3] -> 2
 [4,5,11,12,7,1,3,9,10,6,8,2] -> 1
 [4,2,5,11,12,7,1,3,9,10,6,8] -> 5
 [5,8,6,18,16,9,14,10,11,12,4,20,15,19,2,17,1,13,7,3] -> 3
 [14,5,17,15,10,18,1,3,4,13,11,16,2,12,9,7,20,6,19,8] -> 7

関連する

この関連する課題は、実際の順列のサイクルではなく、それらの数を求めます。サイクル数のみを要求すると、実際のサイクルを回避するアルゴリズムが短くなる可能性があります。


私の質問を気にしないでください、それは質問0ベースの入力が許可されているに記載されています。
orlp

@orlpそれは速かったです!あなたの質問を見ることさえできませんでした
ルイスメンドー

入力としてインデックスを値にマッピングできますか?

1
@Copperマッピングのドメインがその順序でset 1...である場合、そうだと思いますn。マッピングを入力する方法を明確にできますか?データ構造ですか?
ルイスメンドー

@LuisMendoはい、Pythonのようなデータ構造ですdict。の{1: 2, 2: 1}代わりに入力として使いたい[2, 1]

回答:


12

J、4バイト

#@C.

これは、順列が0ベースであることを前提としています。C.直接置換を表すリストを与えられた組み込みのサイクルを使用してリストを出力します。次に、その上で#構成さ@れ、そのリストのサイクル数を返します。

ここで試してみてください。


1
それはずるいよ!:)
orlp

1
ビルトインを禁止すべきだった:-D
ルイスメンドー

2
組み込みは愛です。組み込みは命です。ビルトインが禁止されるともっと楽しくなることに同意します。回答が多すぎる場合は、今すぐルールを変更してください。
マイル

@miles Nah、そのままにしておきます。よくやった!
ルイスメンドー

7

JavaScript、99 98バイト

この溶液は、アレイを想定し、その値(例えばゼロインデックス付きです[2, 1, 0])。

f=a=>{h={},i=c=0;while(i<a.length){s=i;while(!h[i]){h[i]=1;i=a[i]}c++;i=s;while(h[++i]);}return c}

説明

// assumes the array is valid and zero-indexed
var findCycles = (array) => {
    var hash = {};  // remembers visited nodes
    var index = 0;  // current node
    var count = 0;  // number of cycles
    var start;      // starting node of cycle

    // loop until all nodes visited
    while(index < array.length) {
        start = index;  // cache starting node

        // loop until found previously visited node
        while(!hash[index]) {
            hash[index] = 1;    // mark node as visited
            index = array[index];   // get next node
        }
        count++;    // increment number of cycles

        index = start + 1;  // assume next node is right after

        // loop until found unvisited node
        while(hash[index]) {
            index++;    // get next node
        }
    }

    return count;   // return number of cycles
};

3
PPCGへようこそ!素敵な最初の答え!これは、私の経験で見た中で、最高ではないにしても、最高の最初の答えの1つです!良い仕事を続けてください!
GamrCorps

本当にありがとうございます!JavaScriptでラムダを実行する方法を実際に調べる必要がありました。私はまだES6のものにそれほど詳しくありません。
kamoroso94

6

Mathematica、45バイト

Length@ConnectedComponents@Thread[Sort@#->#]&

グラフを生成し、接続されているコンポーネントをカウントします。


6

Mathematica、37 28 27バイト

#~PermutationCycles~Length&

9バイトを保存してくれた@alephalphaと、さらに1バイトを保存してくれた@milesに感謝します。


3
PermutationCycles[#,Length]&
-alephalpha

3
ああそれはきちんとしている。PermutationCycles出力のヘッドを変更するために2番目の引数を取ることができるとは知りませんでした。また、中置記法を使用して別のバイトを保存することもできます#~PermutationCycles~Length&
マイル

1
また、元のソリューションに関して#&は、かなり短いですIdentity。;)
マーティン・エンダー

6

Python、77 69 67バイト

f=lambda p,i=1:i and0 **p[i-1]+f(p[:i-1]+[0]+p[i:],p[i-1]or max(p))

(not p[i-1])次のように行うことができます0**p[i-1]
-xnor

5

ゼリー、12 10 9 バイト

ị³$ÐĿ«/QL

@ Dennisのおかげで1バイト節約できました。

これは1ベースの順列を使用します。前の値を保持しながら、前の順列に達するまで順列を繰り返し適用することで機能します。変更を追跡することにより、そのテーブルの列に沿ったすべての値の軌道を作成します。次に、各列の最小値または最大値を見つけることにより、そのサイクルのラベルを作成できます。次に、ラベルのリストを重複排除し、その長さを取得します。これは、ばらばらのサイクルの数になります。

ここで試してみてください。

説明

ị³$ÐĿ«/QL  Input: permutation p
  $        Chain (ị³) as a monad
 ³           The input p
ị            For each value x, get the value at index x in p
   ÐĿ      Invoke it on p initially, and repeat it on its next value until it returns
           to a previous value and keep track of the results
           This will create a table where each column is the orbit of each value
     «/    Get the minimum value along each column of that table
       Q   Deduplicate
        L  Get the length and return

とてもいいアプローチです!
ルイスメンドー

ị³$ÐĿ«/QL動作するはずです。
デニス

@デニスすごい、それはきちんとしたトリックです!各サイクルは独立しているため、max / minのいずれかを取得し、それをラベルとして使用することで、結果の重複排除+長さを十分に確保できます。
マイル

5

Python、64バイト

l=input()
for _ in l:l=[min(x,l[x])for x in l]
print len(set(l))

このゴルフのコードは偶然にも読みやすいものです。0インデックスを使用します。

各値は、それが指しているもの、指し示された値が指しているもの、および2つの小さい方を指します。十分な繰り返しの後、各要素はそのサイクルの最小要素を指します。その場合、指し示されている個別の要素の数はサイクル数です。

n繰り返しを行うだけで十分です。または、リストが変更されなくなるまで繰り返すことができます。この戦略により、同じ長さの64バイトの再帰関数が得られました。

f=lambda l,p=0:len(set(l*(l==p)))or f([min(x,l[x])for x in l],l)

削減は65バイトでした

lambda l:len(set(reduce(lambda l,_:[min(x,l[x])for x in l],l,l)))

set(_)変換は、に短縮することができる{*_}2つのバイトを保存する、Pythonの3.5。


4

Haskell、111バイト

l!i|l!!i<0=l|1<2=(take i l++[-1]++drop(i+1)l)!(l!!i)
f(x:y)|x>=0=0|1<2=1+f y
c l|l==[-1|x<-l]=0|1<2=1+c(l!f l)

0ベースのインデックスを使用します


4
くそー、あなたは良いプログラミングフォントを持っている方が良い:)1l!i|iIi!!1ll1|
orlp

@orlp、それは111バイトです!:O
グルーブプレックス


3

JavaScript(ES6)、49バイト

a=>a.reduce(g=(c,e,i)=>e<i?g(c,a[e],i):c+=e==i,0)

ゼロベースのインデックスを使用します。説明:reduceg、配列の各要素で内部関数を呼び出すために使用されます。cはサイクル数e、配列要素iは配列インデックスです。要素がインデックスよりも小さい場合は、潜在的なサイクルです。この要素を使用して配列にインデックスを付け、サイクル内の次の要素を再帰的に検索します。元のインデックスで開始または終了した場合、これは新しいサイクルであり、サイクルカウントをインクリメントします。いずれかの時点でインデックスより大きい値が見つかった場合、そのサイクルを後でカウントします。


配列[2,1,0,3,4,5]でコードを実行すると、「最大呼び出しスタックサイズを超えました」というメッセージでクラッシュしました。
kamoroso94

1
@ kamoroso94申し訳ありませんが、タイプミスが入り込んでいました。今すぐ修正する必要があります。
ニール

2

C、90バイト

f()可変int配列、1ベースのインデックス付けで呼び出します。2番目のパラメーターは、配列のサイズです。この関数は、サイクル数を返します。

i,j,c;f(a,n)int*a;{for(c=i=0;i<n;++i)for(j=0,c+=!!a[i];a[i];a[i]=0,i=j-1)j=a[i];return c;}

ideoneで試してみてください

アルゴリズム:

For each index
    If index is non-zero
        Increment counter
        Traverse the cycle, replacing each index in it with 0.

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.