电话号码键数字/字母排列

时间:2015-09-28 23:45:00

标签: algorithm recursion permutation

我正在做一些算法练习并遇到了一个我难以解决的问题。

手机上的每个数字键代表某些字母(例如2 => A, B, C3 => D, E, F等,但10除外。用户可以多次敲击键以“滚动”到不同的字母。例如,222可以是AAAABBAC

给定一个输入字符串,例如444223,这代表什么不同的组合?

您可以假设有一个字典/散列图,其中包含要映射映射的数字。

map = {
  2 => "ABC",
  3 => "DEF",
  4 => "GHI",
  5 => "JKL",
  6 => "MNO",
  7 => "PQRS",
  8 => "TUV",
  9 => "WXYZ",
}

我试图分两部分来解决这个问题。首先,将输入拆分为连续数字的子串数组。例如:["444", "22", "3"]。然后,通过递归算法运行其中的每一个,该算法将输入分解为其基本情况(例如f(4444) -> f(444) -> f(44) -> f(4)),然后求解单个数字并返回链中计算出所有排列。

然而,我无法让它发挥作用 - 我不知道这是否是正确的方法。当数字字符串大于字母数(例如4444)时,我也遇到了问题,因为这可能是两个B s,我认为这不会对我尝试的置换递归算法起作用写。

任何帮助将不胜感激!

2 个答案:

答案 0 :(得分:2)

你在正确的轨道上将相同数字的条纹分解成所有排列。

递归部分最多有三个部分。因此对于4444,第一步分为3个部分:

"4" (G) --> continue on 444
"44" (H) --> continue on 44
"444" (I) --> continue on 4

使用相同的规则继续使用剩下的字符串。

编辑:

由于数据结构的原因,写入伪代码有点复杂。你需要三件事:

  • 包含数字的每个分区的集合
  • 您正在处理的当前设置
  • 正在处理的值(例如上例中的“4”)
  • 剩下相同数字的数量

因此,对于给定的相同数字序列,分区的工作原理如下:

PartitionNums (sets, curset, val, len) {
    if len = 1 then
        insert into sets (curset, val)
    else if len = 2 then
        insert into sets (curset, val)
        insert into sets (curset, val||val)
    else if len = 3 then
        insert into sets (curset, val||val||val)
        ProcessSets(sets, (curset, val), val, len - 1)
        ProcessSets(sets, (curset, val||val), val, len - 2)
    else
        ProcessSets(sets, (curset, val), len - 1)
        ProcessSets(sets, (curset, val||val), len - 2)
        ProcessSets(sets, (curset, val||val||val), len - 3)
}

它会被称为:

ProcessSets({}, '', '4', 5)

对于44444。

这只处理一串相同的数字。然后必须将其编织成代码,分割字符串并从数字序列中查找字符。

答案 1 :(得分:0)

这看起来很酷,所以我在Perl中编写了一个实现。基本前提是将每组数字拆分成连续的数字,然后生成那些数字的所有可能分组,这些数字等于数字串的长度。之后,只需将数字输入映射表,并将结果分组为单个解决方案。

#!/usr/bin/env perl

use strict;
use warnings; 

use Set::Product::PP qw(product);

my %digit_map = (
   2 => [qw(A B C)],
   3 => [qw(D E F)],
   4 => [qw(G H I)],
   5 => [qw(J K L)],
   6 => [qw(M N O)],
   7 => [qw(P Q R S)],
   8 => [qw(T U V)],
   9 => [qw(W X Y Z)],
);

sub decode {
   my (@digits) = @_;

   my $last_digit = $digits[0];
   my @solutions;
   my @consecutive_digits;
   while ( my $digit = shift @digits ) {
      if ( $digit == $last_digit ) {
         push @consecutive_digits, $digit;
      }
      else {
         $last_digit = $digit;
         push @solutions, [ 
            map { _partitions_to_letter($_) } _partitions(@consecutive_digits) 
         ];
         @consecutive_digits = ( $digit );
      }
   }

   if ( @consecutive_digits ) {
      push @solutions, [ 
         map { _partitions_to_letter($_) } _partitions(@consecutive_digits) 
      ];
   }

   my @combined_solutions;
   # compute cartesian product of all partitioned consecutive digits
   product { push @combined_solutions, join '', @_ } @solutions;

   return @combined_solutions;
}

sub _partitions_to_letter {
   my ($partitions) = @_;

   return join '', map { $digit_map{ $_->[0] }->[ @$_ - 1 ] } @$partitions;
}

sub _partitions {
   my (@consecutive_digits) = @_;
   return [ [@consecutive_digits] ] if @consecutive_digits == 1;

   my @partitions = ( 
      # use the current array as a partition
      [ [@consecutive_digits]            ],  
      # each piece of the current array counts as a partition 
      [ map { [$_] } @consecutive_digits ], 
   );
   foreach my $i ( 0 .. $#consecutive_digits - 1) {
      push @partitions, [ 
         [@consecutive_digits[0..$i]],              
         [@consecutive_digits[$i+1..$#consecutive_digits]] 
      ];
   }

   return @partitions;
}

foreach my $solution ( decode(qw(4 4 4 2 2 3)) ) {
   print $solution, "\n";
}
#   IBD
#   IAAD
#   IAAD
#   GGGBD
#   GGGAAD
#   GGGAAD
#   GHBD
#   GHAAD
#   GHAAD
#   HGBD
#   HGAAD
#   HGAAD

很高兴解释任何难以理解的作品。