php给定一个字符串,给定一个字符串,返回所有的可能组合

例:abc

返回a,b,c,ab,ac,bc,ca,cb,abc,acb,bac,bca,cab,cba

回复内容:

例:abc

返回a,b,c,ab,ac,bc,ca,cb,abc,acb,bac,bca,cab,cba

我覺得這個問題相當有趣,做為一個 Python 狂熱者,我不能同意 @garry_qian 的答案更多了,既然 Python 都提供了那麼好用的標準庫,不使用一下實在是太可惜了,在此立場下,一個 簡潔,簡短 (好啦並沒有...),但邏輯上基本相同的做法如下:

>>> s = 'abc'

>>> results = sorted([''.join(c) for l in range(len(s)) for c in permutations(s, l+1)])

['a', 'b', 'c', 'ab', 'ac', 'ba', 'bc', 'ca', 'cb', 'abc', 'acb', 'bac', 'bca', 'cab', 'cba']

這個寫法沒什麼特別的,不過是使用兩個 for 的 list comprehension 罷了。

同時,它回傳的是一個 string 的 list,與原題目比較接近。

但是這激發了我的一些好奇心,想自己來寫寫看,同時以沒有這些排列組合工具的他種語言來說,也許比較容易利用相同的邏輯來完成。

首先我完成的是關於組合的 function,他代入一個字串並且回傳所有長度的所有字元組合,但不排列:

def get_combinations(string):

combs = []

for i in range(1, 2**len(string)):

pat = "{0:b}".format(i).zfill(len(string))

combs.append(''.join(c for c, b in zip(string, pat) if int(b)))

return combs

測試:

>>> print get_combinations('abc')

['c', 'b', 'bc', 'a', 'ac', 'ab', 'abc']

一如預期,我們拿到:

長度為 1 的 'c', 'b', 'a'

長度為 2 的 'bc', 'ac', 'ab'

長度為 3 的 'abc'

果然是各種長度下的所有組合都到手了。

這個寫法肯定不是最好的,但我覺得想法滿有趣的。想法就是,要考慮 'abc' 的所有組合,那不就是分別考慮 a 要不要取,b 要不要取 和 c 要不要取,於是總共 2*2*2 = 8 (2**len(string)) 種組合,那不就正好對應到:

000 -> 都不取

001 -> 只取 c

010 -> 只取 b

011 -> 取 b c

100 -> 只取 a

101 -> 取 a c

110 -> 取 a b

111 -> 都取

所以在 get_combinations 中,用了一點技巧去生出從 1 到 7 的二進位碼,再根據 0 與 1 決定每一種組合該取用那些字元。

這還沒完成任務,我們距離標準答案,還必須取得:

每一種 組合 的所有 排列 情形

這產生了 get_permutations 這個 function:

def get_permutations(clst):

if len(clst)==1:

return [clst[0]]

results = []

for idx, c in enumerate(clst):

results += [c+substr for substr in get_permutations(clst[:idx] + clst[idx+1:])]

return results

測試:

>>> print get_permutations('abc')

['abc', 'acb', 'bac', 'bca', 'cab', 'cba']

邏輯很簡單,用 recursive 的方式去找出 固定長度字元組合 所有的排列。

有了以上兩種 function,我們就可以求出答案囉:

>>> [perm for comb in get_combinations('abc') for perm in get_permutations(list(comb))]

['c', 'b', 'bc', 'cb', 'a', 'ac', 'ca', 'ab', 'ba', 'abc', 'acb', 'bac', 'bca', 'cab', 'cba']

結論:

別重複發明輪胎,這不但累死你,還很顯笨

人生苦短,我用 Python

import itertools

chrs = 'abc'

for i in range(len(chrs)):

for combination in itertools.permutations(chrs, i + 1):

print combination

既然同时打了 php 和 python 标签,那就用两种方式都写下吧,逻辑用的一样的。

php代码

function addChar($strs, $chars) {

$result = [];

foreach ($strs as $str) {

foreach ($chars as $char) {

$result[] = $str . $char;

}

}

return $result;

}

$chars = ['a', 'b', 'c'];

$group = [];

$count = count($chars);

for ($i = 1; $i <= $count; $i++) {

if ($i == 1) {

$group[$i] = addChar([''], $chars);

} else {

$group[$i] = addChar($group[$i - 1], $chars);

}

}

// 合并数组

$result = call_user_func_array('array_merge', $group);

var_dump($group);

python代码

# encoding:utf-8

def addChar(strs, chars):

result = []

for str in strs:

for char in chars:

result.append(str + char)

return result

chars = ['a', 'b', 'c']

group = {}

count = len(chars)

for i in xrange(1, count + 1):

if i == 1:

group[i] = addChar([''], chars)

else:

group[i] = addChar(group[i - 1], chars)

# 合并数组

result = []

for i in group:

result += group[i]

print result

result = []

def function(arg, string):

global result

if len(arg) >= len(string):

return None

for alphabet in string:

if alphabet in arg:

continue

function(arg+alphabet, string)

result.append(arg+alphabet)

string = 'abc'

for alphabet in string:

result.append(alphabet)

function(alphabet, string)

print list(set(result))

python2.7,和@garry_qian 相同,写完才发现有了,其他楼的python方案我都懒得看了

# coding: utf-8

import itertools as t

li = ['a', 'b', 'c']

tmp = []

for n in range(1, len(li) + 1):

x = t.permutations(li, n)

for i in x:

tmp.append(''.join(i))

print tmp

P(2,3)

P(3,3)

12种可能性

假设字符串的长度为2, 那所有的组合就是: 2! + 2! / 1! = 4

假设字符串的长度为3, 那所有的组合就是: 3! + 3! / 1! + 3! / 2! = 15

假设字符串的长度为4, 那所有的组合就是: 4! + 4! / 1! + 4! / 2! + 4! / 3! = 64

这个公式可以进行推广

n! + n! / 1! + n! / 2! + ... + n! / (n-1)!

代码就不贴了

本文原创发布php中文网,转载请注明出处,感谢您的尊重!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值