String Halving
昨晩、String Halving が終了した。面白い問題だった。
sed
sedは結構コンパクトにできたな(83B)と思っていたら、tails さん@70B にあっさり抜かれた。
この問題は、文字列を2分割して、それぞれを中かっこで囲えばいいのだが、2分割するところが工夫のいるところ。考えたのは、2つマーカーを設けて、1ポジションずつ文字列の内側へ向けて寄せていく方法。例示すると以下のよう。
B----------E -B--------E- --B------E-- ---B----E--- ----B--E---- -----BE-----
マーカーとして、中かっこを使えば最も効率がいいのだが、分割をしていくと中かっこが文字列中に現れるので、ほかの文字を使う必要があると思っていた。ところが、tails さんの解を見たら、中かっこを使っていた。確かに、右に動ける右中かっこは一つしか存在しないし、左に動けるものも同様なんだ。
B E {{--}-----{--}{----------}}
この例のように、B と E は簡単に特定できる。
s/}\([^{}]\)/\1}/ s/\([^{}]\){/{\1/
中かっこはマーカーに使えないという思い込みがあったためか、気付けなかった。tails さんさすがです。
JavaScript(と C)
JavaScript は、youz さん@83B に 1B 差で負けた。以下は youz さんの解。
s=readline(i=0) function r(n)"{"+(n<2?s[i++]:r(n/2+.5|0)+r(n>>1))+"}" print(r(919))
特徴的なのは、i を使って、分割しきった長さ 1 の文字列の取り出しを、s[i++] で行っているところだ。入力文字列の先頭から順にアクセスされるということなんだ。試しに、私の解に以下のようにprint()を突っ込んでみたら、
s=readline(f=function(b,e)'{'+(e+~b?f(b,b=b-~e>>1)+f(b,e):(print(b),s[b]))+'}') print(f(0,s.length))
確かに、
0 1 2 3 :
と順に表示された。これは、気づかなかった。
ということは、C では、getchar() で順に読み込んでやればいいんだと思い、自分の解を以下のように変更してみたら 88B ができた。
p(x){putchar(x);}f(l){p('{')+(l>1?f(l+1>>1)+f(l/2):p(getchar()))+p('}');}main(){f(919);}
これは面白いな。もう少し短くなるかも。
追記:
アクセスが文字列の先頭から順に行なわれるというのは、2分木の Depth-First サーチ(日本語ではなんていうんだろう?)だから、ツリーの左から順にアクセスされるということか。