找到给定字符串的每个可能的子集

时间:2015-02-18 22:45:13

标签: java string for-loop arraylist substring

我试图在Java中找到字符串的每个可能的字谜 - 我的意思是,如果我有一个4个字符长的单词,我想要从它派生的所有可能的3个字符的长单词,所有2个字符长,所有1个字符长。我最直接的方法是在字符串上使用两个嵌套的for循环和iterare。这是我现在的代码:

private ArrayList<String> subsets(String word){
        ArrayList<String> s = new ArrayList<String>();
        int length = word.length();
        for (int c=0; c<length; c++){
            for (int i=0; i<length-c; i++){
                String sub = word.substring(c, c+i+1);
                System.out.println(sub);
                //if (!s.contains(sub) && sub!=null) 
                    s.add(sub);
            }
        }
        //java.util.Collections.sort(s, new MyComparator());
        //System.out.println(s.toString());
        return s;
    }

我的问题是,它适用于3个字母的单词,fun这个结果是错的(不要介意排序,处理这个单词,以便我有一个字母顺序排列的字符串):

f
fn
fnu
n
nu
u

但是,当我尝试4个字母的单词时,它会留下一些东西,就像catq给我的那样:

a
ac
acq
acqt
c
cq
cqt
q
qt
t

即,我没有看到3个字符长的单词act - 这是我在测试此方法时所寻找的那个。我无法理解问题是什么,而且这很可能是我在创建子字符串时所犯的逻辑错误。如果有人可以帮助我,请不要给我代码,而是解决方案背后的原因。这是一个课程作业,我需要自己提出代码。

编辑:清除一些东西,对我来说,acq,qca,caq,aqc,cqa,qac等都是一回事 - 为了让它更清晰,会发生什么事情就是字符串按字母顺序排序,因此所有这些排列应该作为一个唯一结果,acq。所以,我不需要字符串的所有排列,而是给出一个4个字符长的字符串,我可以从中得到所有3个字符长的字符串 - 这意味着一次取出一个字符并返回结果是该字符串,对原始字符串中的每个字符执行此操作。 我希望我的问题更清楚了

4 个答案:

答案 0 :(得分:1)

它工作正常,你刚拼错了#34; caqt&#34; as&#34; acqt&#34;在你的测试/输入中。

(问题可能是您要对输入进行排序。如果您需要substrings,则必须保持输入未排序。)

完成修改后:请参阅Generating all permutations of a given string然后只对各个字母进行排序,并将它们放入一组中。

答案 1 :(得分:1)

好的,因为你已经设计了自己的解决方案,我会给你我的看法。首先,考虑一下你的结果列表有多大。你基本上是依次拿走每一个字母,无论是否包含它。每个字母有2种可能性,总共给出2 ^ n个结果,其中n是字母数。这当然包括你不使用任何字母,最后是空字符串的情况。

接下来,如果你列举了每个可能性为0的'包含这封信'而1为不包括它,那么以你的'fnu'为例,你最终得到:

000 - ''
001 - 'u'
010 - 'n'
011 - 'nu'
100 - 'f'
101 - 'fu' (no offense intended)
110 - 'fn'
111 - 'fnu'.

显然,这些只是二进制数,你可以导出一个函数,给出0-7之间的任意数字和三个字母输入,将计算相应的子集。

在java中做起来相当容易..没有手头的java编译器,但这应该近似正确:

public string getSubSet(string input, int index) {
  // Should check that index >=0 and < 2^input.length here.
  // Should also check that input.length <= 31.
  string returnValue = "";
  for (int i = 0; i < input.length; i++) {
    if (i & (1 << i) != 0) // 1 << i is the equivalent of 2^i
      returnValue += input[i];
  }
  return returnValue;
}

然后,如果你需要,你可以做一个调用这个函数的循环,如下所示:

for (i = 1; i < (1 << input.length); i++)
  getSubSet(input, i); // this doesn't do anything, but you can add it to a list, or output it as desired.

注意我从1开始而不是0-这是因为索引0处的结果将是空字符串。顺便说一句,这实际上首先是最不重要的位,所以你的输出列表将是'f','n','fn','u','fu','nu','fnu',但顺序没有'似乎很重要。

答案 2 :(得分:0)

这是我提出的方法,似乎正在运作

private void subsets(String word, ArrayList<String> subset){
        if(word.length() == 1){
            subset.add(word);
            return;
        } 
        else {
            String firstChar = word.substring(0,1);
            word = word.substring(1);
            subsets(word, subset);
            int size = subset.size();
            for (int i = 0; i < size; i++){
                String temp = firstChar + subset.get(i);
                subset.add(temp);
            }
            subset.add(firstChar);
            return;
        }
    }

我所做的是检查单词是否大于一个字符,否则我将单独的字符添加到ArrayList并启动递归过程。如果它更大,我保存第一个字符并使用String的其余部分进行递归调用。会发生的是整个字符串被切换为保存在递归堆栈中的字符,直到我达到我的单词长度为1的点,只剩下一个字符。

当发生这种情况时,正如我在开始时所说,字符被添加到List中,现在递归开始并且它查看数组的大小,在第一次迭代中是1,然后使用for循环添加保存在堆栈中的字符,用于上一次调用与ArrayList中的每个元素连接。然后它自己添加字符并再次展开递归。 I.E.,单词fun会发生这种情况:

f saved
List empty
recursive call(un)
-
u saved
List empty
recursive call(n)
-
n.length == 1
List = [n]
return
-
list.size=1
temp = u + list[0]
List = [n, un]
add the character saved in the stack on its own
List = [n, un, u]
return
-
list.size=3
temp = f + list[0]
List = [n, un, u, fn]
temp = f + list[1]
List = [n, un, u, fn, fun]
temp = f + list[2]
List = [n, un, u, fn, fun, fu]
add the character saved in the stack on its own
List = [n, un, u, fn, fun, fu, f]
return

我已经尽可能清楚了,我希望这可以澄清我最初的问题是什么以及如何解决它。

答案 3 :(得分:0)

这是有效的代码:

public static void main(String[] args) {
    String input = "abcde";
    Set<String> returnList = permutations(input);
    System.out.println(returnList);
}

private static Set<String> permutations(String input) {
    if (input.length() == 1) {
        Set<String> a = new TreeSet<>();
        a.add(input);
        return a;
    }
    Set<String> returnSet = new TreeSet<>();

    for (int i = 0; i < input.length(); i++) {
        String prefix = input.substring(i, i + 1);
        Set<String> permutations = permutations(input.substring(i + 1));
        returnSet.add(prefix);
        returnSet.addAll(permutations);
        Iterator<String> it = permutations.iterator();
        while (it.hasNext()) {
            returnSet.add(prefix + it.next());
        }
    }
    return returnSet;
}