查找一个字母不同的所有单词

时间:2015-10-31 16:30:31

标签: regex perl file

我正在研究一个单词链程序,并给出了两个单词和一个单词文件,程序通过一次只更改一个字母,从一个单词更改为另一个单词,找到如何从一个单词转到另一个单词关闭文件中的文字。

我正在研究一个子程序,该子程序将返回文件中只有一个字母不同的单词列表。

我知道我可能会使用正则表达式来查找单词并将其添加到列表中。感谢有人给予的任何帮助。

#!/usr/bin/perl -w

$start_word = $ARGV[0];
$end_word = $ARGV[1];

my $file = "wordlist.txt";

open (FH, "< $file" ) or die "Can't open $file for read: $!";
my @lines;
while(<FH>)
{
        push (@lines, $_);
}

#print @lines;

#find word diff

#return list of words with 1 letter diff

#recursion to return smallest stack

1 个答案:

答案 0 :(得分:1)

可以轻松优化您的候选人群:链中所有可能的单词必须具有相同的长度。

sub read_all_candidates {
  my($dict,$start) = @_;

  open my $fh, "<", $dict or die "$0: open $dict: $!\n";

  my @pool;
  while (<$fh>) {
    chomp;
    next if length($_) != length($start) || $_ eq $start;
    push @pool, lc $_;
  }

  \@pool;
}

考虑到链中单词的长度,您还可以为该长度的单词构建专门的Regexp实例。

# Computes and caches a Regexp object (created with qr//) that
# matches pairs of one-hop words concatenated one after the
# other (e.g., "doghog" for dog and hog). For example, words of
# length 3 would generate the following pattern:
#
#   ^(.)(.)(.)(?:.\2\3|\1.\3|\1\2.)$
#
# You need only call this sub once per run.
my $_one_hopper;
sub _compute_one_hopper {
  my($length) = @_;

  my $pattern = "^" . "(.)" x $length;

  my @choices;
  foreach my $n (1 .. $length) {
    push @choices => join "", map $_ == $n ? "." : "\\$_", 1 .. $length;
  }

  #print $pattern, "\n";
  $pattern .= "(?:" . join("|" => @choices) . ")\$";

  eval "\$_one_hopper = qr/$pattern/" or die "$0: internal error";
}

中使用$_one_hopper
# Returns one-hop neighbors of $from taken from @$words but that are
# not present in %$seen.
sub one_hop {
  my($from,$words,$seen) = @_;

  $_one_hopper = _compute_one_hopper length $from
    unless defined $_one_hopper;

  grep !$seen->{$_} && "$from$_" =~ /$_one_hopper/, @$words;
}

将所有内容捆绑在一起,您的主循环具有以下结构。

my $words = read_all_candidates $dict, $start;

my $min  = 1;         # minimum number of transitions from $start to
my $seen = {};        # words seen in earlier batches (prevents
my @last = ($start);  # last batch of neighbors

while (@last) {
  my @next;
  foreach my $word (@last) {
    my @onemore = one_hop $word, $words, $seen;
    ++$seen->{$_} for @onemore;
    ...
  }
}