হুম, আমি দুটি সম্ভাব্য আলগোরিদিম মনে করতে পারেন: একটি রৈখিক মাধ্যমে স্ক্যান একজন ক্রম, অথবা সূচকের ধ্রুবক সময় লুকআপ সঙ্গে একটি অভিধান বিল্ডিং।
আপনি যদি একক বৃহত্তর সিকোয়েন্স A এর বিপরীতে অনেকগুলি সম্ভাব্য উপসর্গ B পরীক্ষা করে থাকেন তবে আমি আপনাকে পরামর্শ দিচ্ছি অভিধানের সাথে বৈকল্পিকটি ব্যবহার করুন।
লিনিয়ার স্ক্যান
বিবরণ
আমরা ক্রম এ এর জন্য একটি কার্সার বজায় রাখি । তারপরে আমরা বি উপস্থার সমস্ত আইটেমের মাধ্যমে পুনরাবৃত্তি করব । প্রতিটি আইটেমের জন্য, আমরা কার্সারটিকে A এ এগিয়ে নিয়েছি যতক্ষণ না আমরা কোনও ম্যাচিং আইটেম খুঁজে না পাই। যদি কোনও মিলে যাওয়া আইটেমটি পাওয়া যায় না, তবে বি কোনও উপসর্গ নয়।
এটি সর্বদা ও (সিক.সাইজ) এ চলে ।
সুডোকোড
আবশ্যক শৈলী:
def subsequence? seq, subseq:
i = 0
for item in subseq:
i++ while i < seq.size and item != seq[i]
return false if i == seq.size
return true
কার্যকরী শৈলী:
let rec subsequence? = function
| _ [] -> true
| [] _ -> false
| cursor::seq item::subseq ->
if cursor = item
then subsequence? seq subseq
else subsequence? seq item::subseq
উদাহরণ বাস্তবায়ন (পার্ল):
use strict; use warnings; use signatures; use Test::More;
sub is_subsequence_i ($seq, $subseq) {
my $i = 0;
for my $item (@$subseq) {
$i++ while $i < @$seq and $item != $seq->[$i];
return 0 if $i == @$seq;
}
return 1;
}
sub is_subsequence_f ($seq, $subseq) {
return 1 if @$subseq == 0;
return 0 if @$seq == 0;
my ($cursor, @seq) = @$seq;
my ($item, @subseq) = @$subseq;
return is_subsequence_f(\@seq, $cursor == $item ? \@subseq : $subseq);
}
my $A = [1, 2, 3, 4];
my $B = [1, 3];
my $C = [1, 3, 4];
my $D = [3, 1];
my $E = [1, 2, 5];
for my $is_subsequence (\&is_subsequence_i, \&is_subsequence_f) {
ok $is_subsequence->($A, $B), 'B in A';
ok $is_subsequence->($A, $C), 'C in A';
ok ! $is_subsequence->($A, $D), 'D not in A';
ok ! $is_subsequence->($A, $E), 'E not in A';
ok $is_subsequence->([1, 2, 3, 4, 3, 5, 6], [2, 3, 6]), 'multiple nums';
}
done_testing;
অভিধান অনুসন্ধান
বিবরণ
আমরা ক্রম A এর আইটেমগুলি তাদের সূচকগুলিতে ম্যাপ করি । তারপরে আমরা বি এর প্রতিটি আইটেমের জন্য উপযুক্ত সূচকগুলি সন্ধান করি , সেই সূচকগুলি যেগুলি ছোট। যখন কোনও সূচকগুলি পাওয়া যায় না, তখন বি কোনও উপসর্গ নয়।
ও (সাবক্লিক.সাইজ · কে) এর মতো কোনও কিছুর মধ্যে চলে , যেখানে কে কতগুলি সদৃশ সংখ্যা রয়েছে তা বর্ণনা করে seq
। প্লাস একটি ও (seq.size) ওভারহেড
এই সমাধানটির সুবিধাটি হ'ল একবার আপনি অনুসন্ধানের টেবিলটি তৈরির ওভারহেড প্রদান করার পরে একটি নেতিবাচক সিদ্ধান্তটি খুব দ্রুত (ধ্রুবক সময় পর্যন্ত) পৌঁছানো যায়।
সুডোকোড:
আবশ্যক শৈলী:
# preparing the lookup table
dict = {}
for i, x in seq:
if exists dict[x]:
dict[x].append(i)
else:
dict[x] = [i]
def subsequence? subseq:
min_index = -1
for x in subseq:
if indices = dict[x]:
suitable_indices = indices.filter(_ > min_index)
return false if suitable_indices.empty?
min_index = suitable_indices[0]
else:
return false
return true
কার্যকরী শৈলী:
let subsequence? subseq =
let rec subseq-loop = function
| [] _ -> true
| x::subseq min-index ->
match (map (filter (_ > min-index)) data[x])
| None -> false
| Some([]) -> false
| Some(new-min::_) -> subseq-loop subseq new-min
in
subseq-loop subseq -1
উদাহরণ বাস্তবায়ন (পার্ল):
use strict; use warnings; use signatures; use Test::More;
sub build_dict ($seq) {
my %dict;
while (my ($i, $x) = each @$seq) {
push @{ $dict{$x} }, $i;
}
return \%dict;
}
sub is_subsequence_i ($seq, $subseq) {
my $min_index = -1;
my $dict = build_dict($seq);
for my $x (@$subseq) {
my $indices = $dict->{$x} or return 0;
($min_index) = grep { $_ > $min_index } @$indices or return 0;
}
return 1;
}
sub is_subsequence_f ($seq, $subseq) {
my $dict = build_dict($seq);
use feature 'current_sub';
return sub ($subseq, $min_index) {
return 1 if @$subseq == 0;
my ($x, @subseq) = @$subseq;
my ($new_min) = grep { $_ > $min_index } @{ $dict->{$x} // [] } or return 0;
__SUB__->(\@subseq, $new_min);
}->($subseq, -1);
}
my $A = [1, 2, 3, 4];
my $B = [1, 3];
my $C = [1, 3, 4];
my $D = [3, 1];
my $E = [1, 2, 5];
for my $is_subsequence (\&is_subsequence_i, \&is_subsequence_f) {
ok $is_subsequence->($A, $B), 'B in A';
ok $is_subsequence->($A, $C), 'C in A';
ok ! $is_subsequence->($A, $D), 'D not in A';
ok ! $is_subsequence->($A, $E), 'E not in A';
ok $is_subsequence->([1, 2, 3, 4, 3, 5, 6], [2, 3, 6]), 'multiple nums';
}
done_testing;
অভিধান চেহারা বৈকল্পিক: একটি সসীম স্টেট মেশিন হিসাবে এনকোডিং
বিবরণ
আমরা যদি আরও মেমরিতে বাণিজ্য করি তবে আমরা ও (সাবক.সাইজ) এর নিচে আলগোরিদিম জটিলতা আরও কমাতে পারি। উপাদানগুলিকে তাদের সূচকগুলিতে ম্যাপিংয়ের পরিবর্তে আমরা একটি গ্রাফ তৈরি করি যেখানে প্রতিটি নোড তার সূচকে কোনও উপাদান উপস্থাপন করে। প্রান্তগুলি সম্ভাব্য ট্রানজিশনগুলি দেখায়, উদাহরণস্বরূপ সিকোয়েন্সগুলির a, b, a
প্রান্তগুলি থাকবে a@1 → b@2, a@1 → a@3, b@2 → a@3
। এই গ্রাফটি সীমাবদ্ধ রাষ্ট্রের মেশিনের সমতুল্য।
দেখার সময় আমরা একটি কার্সার বজায় রাখি যা প্রাথমিকভাবে গাছের প্রথম নোড। এরপরে আমরা সাবলিস্ট বিতে প্রতিটি উপাদানগুলির জন্য প্রান্তটি হাঁটাচ্ছি । যদি এ জাতীয় প্রান্তটি বিদ্যমান না থাকে, তবে বি কোনও সাবলিস্ট নয়। যদি সমস্ত উপাদানগুলির পরে কার্সারে একটি বৈধ নোড থাকে, তবে বি একটি সাবলিস্ট।
সুডোকোড
আবশ্যক শৈলী:
# preparing the graph
graph = {}
for x in seq.reverse:
next_graph = graph.clone
next_graph[x] = graph
graph = next_graph
def subseq? subseq:
cursor = graph
for x in subseq:
cursor = graph[x]
return false if graph == null
return true
কার্যকরী শৈলী:
let subseq? subseq =
let rec subseq-loop = function
| [] _ -> true
| x::subseq graph -> match (graph[x])
| None -> false
| Some(next-graph) -> subseq-loop subseq next-graph
in
subseq-loop subseq graph
উদাহরণ বাস্তবায়ন (পার্ল):
use strict; use warnings; use signatures; use Test::More;
sub build_graph ($seq) {
my $graph = {};
for (reverse @$seq) {
$graph = { %$graph, $_ => $graph };
}
return $graph;
}
sub is_subsequence_i ($seq, $subseq) {
my $cursor = build_graph($seq);
for my $x (@$subseq) {
$cursor = $cursor->{$x} or return 0;
}
return 1;
}
sub is_subsequence_f ($seq, $subseq) {
my $graph = build_graph($seq);
use feature 'current_sub';
return sub ($subseq, $graph) {
return 1 if @$subseq == 0;
my ($x, @subseq) = @$subseq;
my $next_graph = $graph->{$x} or return 0;
__SUB__->(\@subseq, $next_graph);
}->($subseq, $graph);
}
my $A = [1, 2, 3, 4];
my $B = [1, 3];
my $C = [1, 3, 4];
my $D = [3, 1];
my $E = [1, 2, 5];
for my $is_subsequence (\&is_subsequence_i, \&is_subsequence_f) {
ok $is_subsequence->($A, $B), 'B in A';
ok $is_subsequence->($A, $C), 'C in A';
ok ! $is_subsequence->($A, $D), 'D not in A';
ok ! $is_subsequence->($A, $E), 'E not in A';
ok $is_subsequence->([1, 2, 3, 4, 3, 5, 6], [2, 3, 6]), 'multiple nums';
}
done_testing;