递归查找字符串(powerset)的所有子集的Java算法
所以,我需要递归地找到给定字符串的所有子集。到目前为止,我得到的是:
static ArrayList<String> powerSet(String s){
ArrayList<String> ps = new ArrayList<String>();
ps.add(s);
for(int i=0; i<s.length(); i++){
String temp = s.replace(Character.toString(s.charAt(i)), "");
ArrayList<String> ps2 = powerSet(temp);
for(int j = 0; j < ps2.size(); j++){
ps.add(ps2.get(j));
}
}
return ps;
我想我知道现在的问题是什么,但我不知道如何解决它。目前,我找到了temp的所有电源组,它们是“bcd”、“acd”、“abd”、“abc”,这将导致重复。有没有办法解决这个问题
对于powerset,我的意思是如果字符串是abc,它将返回“,”a“,”b“,”c“,”ab“,”ac“,”bc“,”abc“
# 1 楼答案
要消除重复,只需将它们全部添加到
Set
中,这可以通过某种帮助器轻松完成:顺便说一句,您的代码本质上处理了边缘情况。你不必为此担心
# 2 楼答案
# 3 楼答案
我发现在设计递归算法时,首先考虑简单的角点情况是很有帮助的,即空字符串和带一个字符的字符串。然后,通常分割问题并对字符串的其余部分/尾部进行递归调用。有点像这样:
# 4 楼答案
没错,您确实有重复项,因为您要多次创建
temp
(每次都没有其他字符),所以当您递归调用时,将有不同的子集共享相同的字符并创建dup。例如,“abc”将创建一个带有:[“ab”、“ac”、“bc”]的temp
,它们中的每一个都将只使用一个字符进行递归调用,因此您将获得“a”、“b”和“c”中的每一个两次避免这种情况的一种方法是使用集合而不是列表,这将省略所有DUP:
现在输出为:
另一种解决方案:
输出
# 5 楼答案
具有n个元素的集合的子集数为2n。例如,如果我们有字符串“abc”,我们将有2个n=23=8个子集
可由n位表示的状态数也是2n。我们可以证明,枚举n位的所有可能状态与包含n个元素的集合的所有可能子集之间存在对应关系:
如果我们考虑第5行,例如,位2和0是活动的。如果我们做
abc.charAt(0) + abc.charAt(2)
,我们得到子集ac
要枚举n位的所有可能状态,我们从0开始,对1求和,直到达到2n-1。在这个解决方案中,我们将从2n-1开始,递减到0,因此我们不需要另一个参数来保持子集的数量,但效果是相同的:
那么你只需要叫它:
并获得所有8个子集:
# 6 楼答案
有一种不使用递归的方法可以做到这一点,它依赖于位字符串和子集之间的简单对应关系
因此,假设您有一个三个字符的字符串“abc”,那么,正如您所指出的,子集将是“,”c“,”b“,”bc“,”a“,”ac“,”ab“,”abc”
如果创建一个字符表,并为子集中的每个字符写入1,为不在子集中的每个字符写入0,则可以看到一个模式:
对于每个长度为n的唯一字符字符串,您将有2个n子集,您可以通过简单地从i=0到i=2n-1创建一个
for
循环来生成所有子集,并且只包含与i
中的位1对应的字符我编写了一个Java示例here和一个C示例here