您的位置:首页 > 其它

滚雪球思路 计算一个字符串所有可能的排列顺序

2012-05-27 00:10 375 查看
今天一同学丢了个问题给我,怎么列出一个字符串所有的排列可能性

刚开始的思路是,先取第一位不同,比如abcd

那取第一位不同的话就有四种可能abcd、bacd、cbad、dcba

这样就想到了用for去循环4次,然后再对后面的组合进行排列

比如abcd,分别取后面三个字母,每个字母出现的位置有三种可能

如:b的话,三个位置为abcd、acbd、acdb

因为结果有重复数据,所以用上了array_unique排重,

后来才发现漏了点什么,因为每次算出来的结果排重后数量都不对

仔细研这分一下发现问题所在

比如abcd中b在第一个位置时,我只算了abcd,漏掉了一种可能就是abdc

至此,前面的想法全部抛弃了。。。

从错误中发现一个问题,就是每两个字母都有可能调整换位置

换言之,要排列所有的可能,就要从最小的组合开始

那么就从两个字母开始排列,假设a和b

可能的顺序为ab 和ba

这时候如果再多一个字母c

那么可能出现的排列变为 cab acb abc和 cba bca bac

从上面能看出来,从最小的组合开始,每当加入一个新的字母时的规律为

用新加的字母对原来的组合中的每一个成员,如上面的ab和ba,分别插入

插入后再将新插入的字母所有可能插入的位置进行计算,

如上面的ab插入c后,c可能出现在左中右

这里可以用一个for循环来完成,

$str = 'ab';
$newstr = 'c'.$str;
$len = strlen($str);
//考虑到后面还要经常使用现在算出来的结果,所以用了一个数组来放置结果
$arr = array();
for($i=0;$i<$len;$i++){
  $arr[] = strtr($newstr,array($newstr[0]=>$newstr[$i],$newstr[$i]=>$newstr[0]));

}


如果只加了一个c,那么这样每次计算出来的结果就是我们想要的结果了

现在给定的字符串是未知的,所以要考虑到一直添加新的字符串到最小的组合中

我想到了用递归来完成这个操作,码出代码如下:

$str = 'abcd';
$len = strlen($str);
$arr = array($str[$len-1]);
$return = '';
getStr($str,$arr,$len-2,$return);
print_r($return);

function getStr($str,$arr,$n,&$return){
if($n>=0){
$newarr = array();
foreach($arr as $v){
$temp = $str[$n].$v;
$l = strlen($temp);
for($i=0;$i<$l;$i++){
$newarr[] = strtr($temp,array($temp[0]=>$temp[$i],$temp[$i]=>$temp[0]));
}
}
getStr($str,$newarr,$n-1,$return);
} else {
$return = $arr;
}
}


写完之后发现用递归有些浪费了,完全没有必要。。。对上面的代码做了下优化,最终结果如下:

$str = 'abc';
$return = getStr($str);
print_r($return);
function getStr($str){
$len = strlen($str);
$arr = array($str[0]);
for($i=1;$i<$len;$i++){
$newarr = array();
foreach($arr as $v){
$temp = $str[$i].$v;
$l = strlen($temp);
for($j=0;$j<$l;$j++){
$newarr[] = strtr($temp,array($temp[0]=>$temp[$j],$temp[$j]=>$temp[0]));
}
}
$arr = $newarr;
}
return $arr;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐