• ベストアンサー

最長の共通部分

はじめて質問させていただきます。 二つのデータの最大長の共通部分を求めるための、 なるだけ高速なアルゴリズムを探しています。 たとえば、 データ1:『EFGABCDEFGABCDEFGHAABCDEFG』 データ2:『EFGHABCDEFGABCDEFGAABCDEFG』 ですと データ1の4バイト目のAから始まる14バイトと データ2の5バイト目のAから始まる14バイトが一致。 が求めたい答えです。 細かい条件をならべると、 1) 文字列ではなくバイナリデータである。 2) データサイズは、最大で数MB程度を想定。 3) 同じ並びの繰り返しなどを多く含んでいる可能性を否定できない。 4) 連続した1つのバイト列で最長なものが知りたい。 5) まれに最長ではなく、最長から二番目が出力されてしまう程度の、 誤差はあってもよい。 6) 一定長(例えば全体の10%)以下の共通部分であれば、無視してもよい。 といった感じなのですが。 ソートを使う、ハッシュを使う、飛び飛びに探索する等、 いろいろアルゴリズムを考えてみましたが、どれもパッとしません。 先ほどグーグルで検索していて、どうやらかなり難しいらしい ということに気づきました。 なにか、ご存知の方いらっしゃいましたら、 アドバイスをお願いいたします。

質問者が選んだベストアンサー

  • ベストアンサー
回答No.3

あまり良く考えてませんが、Trei構造だともしかするといけるかも知れない。 Trei構造は木構造をベースにしてますが、 長男次弟構造を使うと数千万ノードの木が実現できます。

mizuneko
質問者

お礼

>あまり良く考えてませんが、 >Trie構造だともしかするといけるかも知れない。 回答ありがとうございます。 アルゴリズムの本を読んだときに、 トライ構造はなんとなく難しそうなので読まなかったのを、 思い出しました。 これはよいかもしれません。 調べていくうちに、自分で考えたアルゴリズムが、 サフィックスアレイとかいうのと近そうなので、 それに気持ちが傾いているのですが、 文字列比較の計算量がばかにならなくてどうしたものかと迷っています。 正確なことはわかりませんが、トライ構造をうまく改造できれば、 ソートの計算量をさげられるかもしれません。 よい情報をありがとうございました。

その他の回答 (4)

  • sha-girl
  • ベストアンサー率52% (430/816)
回答No.5

#1です。 表のサイズに関しては対角線以外の領域をある程度無視すれば かなりメモリを節約できると思います。 ご指摘の通り データ1:『ABCDF/ABCEFG』 データ2:『ABCEFG/ABCDF』 なら最長一致は 「/ABC」という事になる可能性があります。 その代わり計算量は少なく非常に高速です。 勿論DPマッチングを応用して一致項目が多い順に何パターンか保存し 「ABCEFG」同士が一致してるという事を導く事も可能だと思います。 その辺は精度と速度のトレードオフになると思います。

mizuneko
質問者

お礼

再度の回答ありがとうございます。 >表のサイズに関しては対角線以外の領域をある程度無視すれば >かなりメモリを節約できると思います。 よく考えてみましたが、少ししかずれたらダメということですから、今度は、 データ1:『ABCDF121212』 データ2:『789123ABCDF』 の『12』にヒットするはずで、これはこれでダメなのではないでしょうか。 >データ1:『ABCDF/ABCEFG』 >データ2:『ABCEFG/ABCDF』 >勿論DPマッチングを応用して一致項目が多い順に何パターンか保存し >「ABCEFG」同士が一致してるという事を導く事も可能だと思います。 これも考えて見ましたが、 こういう2ブロックが入れ替わっているだけの 単純なデータならばよいのですが、 現実には、もっと多くのブロックで構成されているデータが、 並べ変わっているといると、まったく関係のないところにヒットしそうで、 怖いです…。 私の実力がないのが一番の問題かもしれませんねorz。 というわけで、今回は迷った末、DPマッチングを使わずに 自作の適当なアルゴリズムで行くことにしましたが、 面白いアルゴリズムを教えていただいて、ありがとうございます。 大変、勉強になりました。

回答No.4

#3のものです。 間違えた。Trei構造ではなく、Trie構造です。 ちなみに、読み(トライです)に引きずられて間違ってしまった。

  • neKo_deux
  • ベストアンサー率44% (5541/12319)
回答No.2

> 5) まれに最長ではなく、最長から二番目が出力されてしまう程度の、誤差はあってもよい。 > 6) 一定長(例えば全体の10%)以下の共通部分であれば、無視してもよい。 > いろいろアルゴリズムを考えてみましたが、どれもパッとしません。 の条件ですと「遺伝的アルゴリズム(GA)」がそこそこ良い結果を出せるのでは?と思います。 MSのサイトが分かりやすいです。 アルゴリズム入門 : 第 5 章 知識情報処理入門 http://www.microsoft.com/japan/msdn/academic/Articles/Algorithm/05/ -- ただ、難しいのは評価式、符号化の選択方法ですね。 No.1さんの参考URLの末尾にもある、 | いずれにせよ、HMMのモデルの格好を定めることは、深遠で時として悩ましい問題です。 のような問題はついて回ります。

参考URL:
http://www.microsoft.com/japan/msdn/academic/Articles/Algorithm/05/
mizuneko
質問者

お礼

遺伝的アルゴリズムですか。 まったく思い浮かびませんでした。 そういう使い方があるのですね。 探索にかける時間に制限がある場合は良さそうですし、 データが巨大な場合はこれが一番いいかもしれません。 >ただ、難しいのは評価式、符号化の選択方法ですね。 >No.1さんの参考URLの末尾にもある、 難しいですね。 やってみたいですが、私にできるでしょうか。 回答ありがとうございました。

  • sha-girl
  • ベストアンサー率52% (430/816)
回答No.1

「DPマッチング」で検索してみてください。 http://staff.aist.go.jp/toru-nakata/dpmatching.html

mizuneko
質問者

お礼

回答ありがとうございます。 せっかく教えていただいた、DPマッチングですが、 どうやったら今回のケースに、このアルゴリズムが使えるのか、 私にはどうも理解できませんでした。 もう少し質問させてください。 参照サイトの説明文を読む限り、得られるのは、 不連続のバイト列なんですよね??。 4) 連続した1つのバイト列で最長なものが知りたい。 なので、そこから連続したバイト列を得ないと いけないのですが、うまい方法が見つかりません。 DPマッチングですと、たとえば、 データ1:『ABCDF/ABCEFG』 データ2:『ABCEFG/ABCDF』 なら データ1の1バイト目から始まる飛び飛びの『ABCF/ABCF』と データ2の1バイト目から始まる飛び飛びの『ABCF/ABCF』が一致 と得られるのでしょうけれど、そこから正しい答え データ1の7バイト目から始まる『ABCEFG』と データ2の1バイト目から始まる『ABCEFG』が一致 を導くのが困難です。 実際もっと複雑なデータですし、 あちらこちらでデータが入れ替わっていたりすると、 どんどん得られるデータと欲しいデータが 無関係になっていくのではないでしょうか。 と疑問に思うのですがどうでしょうか。 それから、 2) データサイズは、最大で数MB程度を想定。 なので、たとえばデータが3MBで、 コストを表すのにINT形を用いたとすると、 表のサイズが、 3M×3M×4B=36TB と巨大になってしまって、メモリーはおろか、 ハードディスクにも入りません。 といって、何度も表をつくり直していては遅くなってしまいますし、 どうしたらよいのでしょうか?。

関連するQ&A

  • 探索・整列アルゴリズムのメリット・デメリットについ

    「コンピューターはなぜ動くのか?」の第5章の「アルゴリズムと仲良くなる7つのポイント」のところにて、主な定番アルゴリズムとして、 表5.1 主な定番アルゴリズム (1)ユーグリットの互除去 (2)エラトステネスのふるい (3)線型探索 (4)2分探索 (5)ハッシュ法 (6)バブル・ソート (7)クイック・ソート 上記のアルゴリズムがあり、そのアルゴリズムの用途には (1)最大公約数のアルゴリズム (2)素数のアルゴリズム (3)データ探索のアルゴリズム (4)整列のアルゴリズム 上記のアルゴリズムがありますが、(3)~(4)のアルゴリズムの用途においてのメリット・デメリット ・データ探索のアルゴリズム (3)線型探索 (4)2分探索 (5)ハッシュ法 についてのメリット・デメリット ・整列のアルゴリズム (6)バブル・ソート (7)クイック・ソート についてのメリット・デメリット これらを教えて頂けばと思っております。 よろしくお願いたします。

  • 定番アルゴリズムのメリット・デメリットについて

    定番アルゴリズムとして以下のアルゴリズムが挙げられますが、 (1)ユークリッドの互徐法 (2)エラトステネスのふるい (3)線型探索 (4)二分探索 (5)ハッシュ探索 (6)バブル・ソート (7)クイック・ソート ↑これらの各々のアルゴリズムのメリット・デメリットについてをそれぞれ教えてください。 よろしくお願いします。

  • アルゴリズムの問題教えてください。

    アルゴリズムの勉強をしています。 とりあえず2分探索、ソート各種、 リスト、ハッシュ、2分木AVL木は実装できました。 ほかに定番のアルゴリズムってありますか。 (正規表現は難しすぎて挫折しました。)

  • アルゴリズムでわからない問題があります。(C言語)

    問題1:探索アルゴリズムであるハッシュ法について正しいものを選べ。 (1)ハッシュ関数の出力によりデータを格納した配列の先頭から順番に調べる. (2) 入力データを,ハッシュ関数の出力により求めた格納場所に基づいて,あらかじめ木構造に格納しておく. (4) 入力データを格納した配列を繰り返し2つに分割し,それぞれを順番に調べていく. (3) 入力データから格納場所の位置に変換する関数(ハッシュ関数)の出力により,データの探索場所を決定する。 (5) 入力データを,ハッシュ関数の出力により求めた格納場所に基づいて,あらかじめヒープに格納しておく 問題2:探索アルゴリズムであるハッシュ法について正しくないものを選べ。 (1)入力データはハッシュ値で決められる場所に格納される. (2) ハッシュ関数には,異なる入力の値に対し異なる値を出力することが求められる. (3) ハッシュ関数の時間計算量は,入力データのサイズに比例する. (4) データの格納場所が大きい方が効率がよい. (5) 一般に2分探索法より高速に動作する. どなたかアルゴリズムに詳しい方回答お願いします

  • ハッシュ探索とはどういうイメージなのか?

    ハッシュ探索というのは「対象となるデータから一定の手順で算出したハッシュ値を用いてデータ本体の代わりに比較に用いる方式」ということですが、どういうものなのかイメージが思いつきません。 これはつまり、データ本体を「ハッシュ」という文字列に変換して、ハッシュ値として出力したものを、比較する(全ての文字列において比較する)というイメージでよいのでしょうか? もしそうだとしたら、ハッシュ値の長さ(文字列の長さ)に応じて(比較)処理時間が変わってくるのでしょうか? 例えば、(あくまで例です。) 6文字程度のハッシュ値→0.2秒で(比較処理時間が)終わる 3万文字程度のハッシュ値→3秒ぐらい(比較処理時間が)かかる ↑こういう風にハッシュ探索は文字列の長さに応じて処理時間が変化するのでしょうか? 回答のほうお願いします。

  • 2次元ハッシュ または 2次元配列をソートしたい

    2次元ハッシュのソートをしたいです。 ハッシュは2つのキーを使用していて、 1つ目のキーは文字列、2つ目のキーは数字(0からの連番)です。 ハッシュの中身は文字列が入っています。 これを次のような表に見立てて、特定の列でソートしたいのです。 hash['a']['0'], hash['a']['1'], ..., hash['a']['50'], hash['q']['0'], hash['q']['1'], ..., hash['q']['50'], hash['c']['0'], hash['c']['1'], ..., hash['c']['50'], ... hash['d']['0'], hash['d']['1'], ..., hash['d']['50'], 例えば 6列目の値によってソートするということです。 以下のようにソートしようとしましたが、うまくいきません。 my @sorthash = sort { $a->[6] <=> $b->[6] } @hash; 何かヒントがあれば教えてください。

    • ベストアンサー
    • Perl
  • アルゴリズムに関する問題

    こんばんわ、いくつかの問題につまってしまったので解答と簡単な解説をお願いします; 【問1】 4桁の数字( a1a2a3a4 )をハッシュ法を用いて配列に格納したい。 ハッシュ関数をmod( a1 +a2 +a3 +a4 ,5 )とし、求めたハッシュ関数値に対応する位置の配列要素に格納する場合、9576は(ア)~(オ)のどこに入るか。 ここでmod(x,5)の値は、xを5で割った余りとする。 位置  配列 0  (ア) 1  (イ) 2  (ウ) 3  (エ) 4  (オ) 【問2】 相違なるn個のデータが昇順に整列された表がある。この表を1ブロックm個に分割し、各ブロックの最後尾のデータだけ線形検索することによって、目的のデータを探し出す。 次に当該ブロック内を線形検索して目的のデータを探し出す。 このときの平均探索(比較)回数は(ア)~(エ)のうちどれか。 ここでm<nとし、目的のデータは必ず表の中に存在するものとする。 (ア)  (イ)  (ウ)  (エ)  n    n          n    m n  ─    ─    m + ─   ─+─  m    2m         m    2 2m 【問3】 次の手順はシェルソートによる整列を示している。 データ列”7,2,8,3,1,9,4,5,6”を手順(1)~(4)に従って整列すると手順(3)を何回繰り返して完了するか。 ここで、〔〕は小数点以下を切り捨てる。 <手順> (1)〔データ数÷3〕→Hとする。 (2)データ列を互いにH要素分だけ離れた要素の集まりからなる部分列とし、それぞれの部分列を挿入方を用いて整列する。 (3)〔H÷3〕→Hとする (4)Hが0であればデータ列の整列は完了し、0でなければ(2)に戻る。 以上になります。

  • 一意(ユニーク)かつ、ソートに対してランダムなIDの発行方法

    随時増加するあるデータに対して、一意なIDを割り当ててゆきます。 通常は、1, 2, 3, … と連番を割り当てて行けば一意なIDになると思います。 その上で、IDでソートした時に発行順に並ぶのではなく、順番がランダムになるようにしたいのです。 (アルゴリズムを知らない人から、発行順を推測されないようにしたい。) そこで考えたのが、"1", "2", "3", …という文字列に対するハッシュ(SHA1やMD5)ですが、sha1("1"), sha1("2"), sha1("3"), …とIDを発行していった場合、IDが重複してしまう可能性を心配しています。(とても低い確率ではあることは分かっていますが、皆無ではありません。) ハッシュ関数を利用する他に、「一意」で「ランダム」で「衝突の可能性がゼロ」である文字列の生成方法はありませんでしょうか?(可能性がゼロというのは物理的に不可能だと思うので、例えばSHA-1であれば、160bitのハッシュが生成されますが、2^160個のIDを発行しても重複しない、ということを考えます。) 一応、規模は1000万ID程度を考えていますが、もっと大きなオーダーでも衝突しないに越したことはありません。

  • PHPとjavascriptで共通なエンコード方法

    PHPからjavascriptにバイナリデータ(16バイト程度)を受け渡す 処理を作成しているのですが、うまく動作しないので、相談します。 バイナリデータをエンコードしてPHPからjavascriptに 以下の流れで引き渡しています。 (1)PHPのbase64_encodeでバイナリデータをエンコード (2)エンコードしたデータをjavascriptに出力 (3)javascriptでデータをデコード (3)のデコードには次のページのbase64.jsなど、いくつかの デコード方法を試してみました。 http://www.onicos.com/staff/iz/amuse/javascript/expert/ しかしながら(1)の元のデータと(3)でデコードしたデータが 一致しません。 質問したいのは以下の2点です。 ・PHPのbase64_encodeとjavascriptのbase64エンコードは  一般的に方式が違うのでしょうか。同じbase64なので  同じコードが生成されると考えたのですが、そうでは  ないのでしょうか。 ・base64_encodeでも、その他の方法でもかまわないので  PHPとjavascriptで共通なエンコード方式、あるいは  PHP上のバイナリデータをjavascriptに正しく受け渡す  方法があれば教えて下さい。 よろしくお願いします。

  • クイックソート

    クイックソートのアルゴリズムの問題で 9 1 8 5 3 4 2 6 7 と上記のようなデータ列を昇順に整列するときに 9 1 8 5 3 4 2 6 7 6 1 8 5 3 4 2 9 7 6 1 2 5 3 4 8 9 7 とここで詰まってしまうんですけどどうしたら昇順に導けますか?