対角バロウズ・ウィーラー変換を解く


11

前書き

この課題では、対角線のバロウズウィーラー変換を解きます。以下は、対角バロウズ・ウィーラー変換とは何かの一般的な概要です。メッセージをエンコードするには、最初にメッセージの長さが奇数(5、7、9など)であることを保証する必要があります。その後、あなたは、グリッドを作るnことにより、n場所、nメッセージの長さがあります。最初の行は元のメッセージです。その後の各行はその上の行ですが、1文字左にシフトし、最初の文字が後ろに移動します。例えば:

Hello World
ello WorldH
llo WorldHe
lo WorldHel
o WorldHell
 WorldHello
WorldHello 
orldHello W
rldHello Wo
ldHello Wor
dHello Worl

次に、NWの各文字をSE対角線上に取り、新しい文字列に入れます。

Hello World  H
ello WorldH  l
llo WorldHe  o
lo WorldHel  W
o WorldHell  r
 WorldHello  d
WorldHello   e
orldHello W  l
rldHello Wo  (space)
ldHello Wor  o
dHello Worl  l

エンコードされたメッセージはHloWrdel olです。デコードするには、まずエンコードされたメッセージの長さを取得し、1を追加して2で除算しxます。この番号を呼び出しましょう。これxで、最初の文字から始めて、各文字がx最後の文字の後にループしていることがわかりました。例えば:

H   l   o   W   r   d   e   l     o   l
1   

Then...

H   l   o   W   r   d   e   l     o   l
1                       2

And again...

H   l   o   W   r   d   e   l     o   l
1   3                   2

Until you get...

H   l   o   W   r   d   e   l       o   l
1   3   5   7   9  11   2   4   6   8  10

今すぐ正しい順序で文字を並べ替えてHello Worldください!

チャレンジ

あなたの課題は、2つのプログラム、関数、またはそれぞれの1つを書くことです。ただし、両方とも同じ言語を使用する必要があります。最初のプログラムは、STDIN、プログラム引数、または関数パラメーターを介して文字列を入力として受け入れ、このメソッドを使用してエンコードします。2番目のプログラムは、STDIN、プログラム引数、または関数パラメーターを介して入力として文字列を受け入れ、このメソッドを使用してそれをデコードします。

必要条件

最初のプログラム/機能

  • 上記の方法を使用した単一の文字列入力。
  • 対角線のBurrows-Wheeler変換スタイルを使用して文字列をエンコードする必要があります。

2番目のプログラム/機能

  • 上記の方法を使用した単一の文字列入力。
  • 対角線のBurrows-Wheeler変換スタイルを使用して文字列をデコードする必要があります。

制約

  • このタスクを実行する組み込み関数または外部関数は使用できません。
  • 標準の抜け穴は許可されていません。
  • 両方のプログラム/機能は同じ言語である必要があります。

得点

これはコードゴルフであるため、バイト単位の最短プログラムが優先さます

さらに情報を追加する必要がある場合は、コメントを残してください!


2
偶数長の入力文字列を奇数長に変換する必要がありますか?
オプティマイザー

5
これは、Burrows-Wheelerの変形ではありません。
-FUZxxl

3
Burrows-Wheeler変換は、最後のアイテムを取得する前にすべての回転の配列が辞書式にソートされるという点で異なります。
-FUZxxl

@Optimizerは必要ありません。
-GamrCorps

回答:


12

CJam、(4 + 8 =)12バイト

エンコードプログラム:

q2/z

こちらからオンラインでお試しください

デコードプログラム:

q_,2/)/z

こちらからオンラインでお試しください

彼らがどのように(またはむしろ、なぜ)働くのか

Diagonal Burrows-Wheeler変換は、基本的に文字列の他のすべての文字であり、最後から折り返します。Stringを2列の2Dマトリックスとして扱う場合、単純に要約すると、マトリックスの変換を取得することになります。例:

Hello World

2D行列として表されます

He
ll
o 
Wo
rl
d

今、列ごとにそれを単に読んで、与えます:

HloWrdel ol

これは、Burrows-Wheeler変換です。

デコードは単純にプロセスの逆で、文字列を2行の2Dマトリックスとして書き込み、列ごとに読み取ります。

コード拡張

エンコーダー:

q          "Read the input";
 2/        "divide it into sub arrays of 2 characters";
   z       "Take transform";

デコーダ:

q_,        "Read the input, take copy and get length of copy";
   2/      "Divide the length by 2";
     )/    "Increment and split the input into two rows";
       z   "Take transform";

7

Python 2、61バイト

E=lambda x:x[::2]+x[1::2]
D=lambda y:(-~len(y)/2*y)[::len(y)/2+1]

E暗号化とD復号化。私は数えていないよE=D=スコアのために。

復号化は、文字列の長さの半分が切り上げられるすべてnの文字の回り込みをn取ります。その理由は、この反転はということです2し、n逆関数は、そう、すべて取って、文字列の長さを法されているnすべての服用番目の文字が反転2ND 1を。

単一の関数の使用が許可されている場合、44バイトを実行できます

def F(x,b):n=1+len(x)**b>>b;return(n*x)[::n]

とき暗号化bされFalse、いつ復号化bですTrue。式1+len(x)**b>>bはに等しい[2,len(x)/2+1][b]です。


4

J、10 + 10 = 20

   ({~#|2*i.@#) 'Hello World'
HloWrdel ol

   (/:#|2*i.@#) 'HloWrdel ol'
Hello World

(周囲の中括弧は関数定義の一部ではないため、スコアにはカウントされません。)

FUZxxlに3バイトの改善をありがとう。

最初の関数はリストで定義された位置から文字を取得し#|2*i.@#、2番目の関数は順序付けと同じリストを使用して文字を並べ替えるため、2つの関数は逆であることがわかりました。

こちらからオンラインでお試しください。


最初の1つも10文字で実行できます{~#|2*i.@#
-FUZxxl

@FUZxxlありがとう、更新しました。これで、2つの関数間の関係が非常にうまく表示されます。
randomra

3

Pyth-5 + 11 = 16バイト

パターンに気づいた!〜幸せなダンスをします〜変換は、文字列をループして他のすべての要素を選択するだけです。そうしないと、要素の半分を取得できないため、奇数でのみ機能します。これは、幅2のマトリックスを回転させるのと同じです。

エンコーダー:

%2*2z

Pythonのステップスライシングはループしないため、文字列を繰り返しました。

%2      Take every other elements
 *2z    Double input string

デコーダ:

K/hlz2%K*Kz

繰り返しますが、ステップスライスのラップアラウンドはありません。

K/hlz2       K=length of (input+1)/2
%K           Every kth element
 *Kz         From K*the input

@FryAmTheEggman奇妙な長さの文字列のみを受け取ることになっていると確信しています 説明の冒頭にありました。
マルティセン

おっと、ごめんなさい。:S
FryAmTheEggman

2

GNU sed -r、(20 + 104 + 1)= 125

スコアの余分な+1は、sedの-rオプション用です。奇数の長さの入力文字列が想定されます。

エンコーダー:

s/.*/&&/
s/(.)./\1/g
  • 入力文字列を2倍にする
  • 奇数(1からカウント)文字ごとにドロップします

デコーダ:

デコーダは:一時的なマーカー文字として使用するため、入力文字列に表示される場合、未定義の動作が発生します。入力文字列が95個のASCII文字に制限されている場合、これらのマーカーをASCII範囲外のもの(BEL 0x7など)に置き換えて、これを修正できます。

s/.*/:&:/
:l;s/:(.)(.+)(.):/\1:\2:\3/;tl
s/:(.*)/\1:/
:m;s/(.)(.*):(.?)(.*):(.*)/\2:\4:\5\1\3/;tm
s/://g
  • :入力文字列の最初と最後にマーカーを置きます
  • 最初のシャッフル:順方向および第二:までの時間における後方1文字を:マーカーは中間文字のいずれかの側です
  • 最初:を削除:し、最後に「A:B:」を残して別の行を追加します。ここで、Aはプレーンテキスト入力からの奇数文字で構成される文字列、Bは偶数文字で構成される文字列です
  • :プレーンテキスト入力を再構築するために、最後の後にAとBの文字を一緒にさざめく
  • 残りの:マーカーを削除します

2

JavaScript ES6、41 + 49 = 90バイト

エンコーダー

(t=>t.replace(/./g,(_,o)=>t[o*2%t.length]))('Hello World')

デコーダ

(t=>t.replace(/./g,(_,o)=>t[-~(l=t.length)/2*o%l]))('HloWrdel ol')

これらは匿名関数なので、関数定義全体であるため、括弧内のコードのみをカウントします。以下のスニペットで試してください:(ES5を使用するように変更)


これはどう[t=>t.replace(/./g,(_,o)=>t[o*2%t.length]),t=>t.replace(/./g,(_,o)=>t[(1+(l=t.length))/2*o%l])]ですか:?あなたは次のようにそれを使用[...][0]('encode string')して[...][1]('decode string')。これができないということは何もありません!そして、1バイトを節約します。
イスマエルミゲル

おかげで、2つの関数を書くように言っていますが、これは重要ではないと思います。
NinjaBearMonkey

それはまだ2つの機能です。ルールは、関数にアクセスするための名前や方法を指定しません。2つの関数を使用する必要があるとしか書かれていません。
イスマエルミゲル

1
@IsmaelMiguel考えてみると、匿名関数は自分で許可されていると思うので、それを使用するとさらに多くのバイトを節約できます。
-NinjaBearMonkey

バイト数を減らしてくれてうれしいです。
イスマエルミゲル
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.