Java - 获取字符串的每个子字符串的所有排列,子串和排列

时间:2014-08-26 01:54:33

标签: java string

首先,我首先要说英语不是我的第一语言所以我为任何不好的解释道歉。

我想知道如何使用这么多不同的订单获取String的每个子字符串。在你告诉我之前已经问过这个问题之前,我想说几乎我看到的这个任务的每个代码实现都没有重复。但是我说我有一个字符串“环境”,我希望每个子字符串包括“ment”,“met”,“ten”,“net”,“note”,“more”等等,我将如何实现这个?

这是我写的功能。

     public static ArrayList<String> getAllSubstringsOfAString(String inputString)
     {
     ArrayList<String> allSubstrings = new ArrayList<String>();
     String sub;
     for(int i = 0; i < inputString.length(); i++)
     {
        for (int j = 1; j <= inputString.length() - i; j++)
        {
            sub = inputString.substring(i , i + j);
            allSubstrings.add(sub);
        }
      }
      return allSubstrings;
     }

当我运行此功能时

    public static void main(String[] args) throws IOException {
    ArrayList<String> allSubStrings = getAllSubstringsOfAString("environment");
    for (String allSubString : allSubStrings) {
        System.out.println(allSubString);
    }

打印出来

    e
    en
    env
    envi
    envir
    enviro
    environ
    environm
    environme
    environmen
    environment
    n
    nv
    nvi
    nvir
    nviro
    nviron
    nvironm
    nvironme
    nvironmen
    nvironment
    v
    vi
    vir
    viro
    viron
    vironm
    vironme
    vironmen
    vironment
    i
    ir
    iro
    iron
    ironm
    ironme
    ironmen
    ironment
    r
    ro
    ron
    ronm
    ronme
    ronmen
    ronment
    o
    on
    onm
    onme
    onmen
    onment
    n
    nm
    nme
    nmen
    nment
    m
    me
    men
    ment
    e
    en
    ent
    n
    nt
    t

这只是我想要的一小部分。我希望函数能够在每个顺序中获得子串。例如,如果我希望它包含像“net”,“ten”,“never”e.t.c这样的字符串,因为它们都是“环境”一词的子串。为实现这一目标,我必须对我的功能做出哪些改变?

另外,由于我是Java初学者,我想知道如果我的代码写得很好,我可以对代码做出哪些更改,使其表现更好,看起来更好,并遵循常见的Java编码约定。< / p>

提前致谢

2 个答案:

答案 0 :(得分:2)

1)生成所有子串(你已经得到了那个部分)

2)为每个子字符串生成所有它的排列 - 您可以使用位向量递归或迭代地执行它(这里已经显示了如何做到这一点,快速谷歌搜索也将给你一些提示)

3)将所有内容添加到最终列表中,这将为您提供已有的内容,反转版本以及所有其他排列

例如&#34; abc&#34;你会得到:

  
      
  • a(1 char,1 permutation)
  •   
  • ab(substring)   
        
    • ba(substring permutation)
    •   
  •   
  • abc(substring)   
        
    • bca(substring permutation)
    •   
    • bac(substring permutation)
    •   
    • acb(substring permutation)
    •   
    • cab(substring permutation)
    •   
    • cba(substring permutation)
    •   
  •   

请注意,计算可能需要一些时间,当字符串为N时,它有N!排列,你将为每个子字符串调用它,所以N次将产生O(N * N!)时间复杂度。

正如@ PM77-1指出的那样,如果我们的字符串有像abcabc这样重复的子串,这可能会做很多不必要的工作。在这种情况下,在每次新迭代之前,您可以检查给定的子字符串是否已经在集合中(是的,您将结果列表更改为具有O(1)查找的集合)并且如果它已经存在则跳过它。

答案 1 :(得分:1)

this other question的帮助下,我把它放在一起。

public static void main(String[] args) {
    List<String> list = perms("codes");
    list.forEach(s -> System.out.println(s));
}

public static List<String> perms(String string) {

    List<String> result = new ArrayList<String>();
    char[] values = string.toCharArray();
    for (int width = 1; width <= values.length; width++) { // for every length
        int stack[] = new int[width];
        for (int i = 0; i < stack.length; i++) { // start from a specific point without duplicates
            stack[i] = stack.length - i - 1;
        }
        int position = 0;
        while (position < width) {

            position = 0;
            StringBuilder sb = new StringBuilder();
            while (position < width) { // build the string
                sb.append(values[stack[position]]);
                position++;
            }
            result.add(sb.toString());
            position = 0;
            while (position < width) {
                if (stack[position] < values.length - 1) {
                    stack[position]++;
                    if (containsDuplicate(stack) == false)
                        break;
                    else
                        position = 0;
                } else {
                    stack[position] = 0;
                    position++;
                }
            }
        }
    }
    return result;
}

private static boolean containsDuplicate(int[] stack) {
    for (int i = 0; i < stack.length; i++) {
        for (int j = 0; j < stack.length; j++) {
            if (stack[i] == stack[j] && i != j) {
                return true;
            }
        }
    }
    return false;
}

除非该单词包含两次该字母,否则不会重复使用该单词中的字母 在这种情况下会有双打 它没有使用递归,因此堆栈溢出不会成为问题。