【问题标题】:Java - Get All Permutations, Substrings and Permutations of every Substring of a StringJava - 获取字符串的每个子字符串的所有排列、子串和排列
【发布时间】:2014-08-26 01:54:32
【问题描述】:

首先,我要说英语不是我的第一语言,所以对于任何糟糕的解释,我深表歉意。

我想知道如何获取具有这么多不同顺序的字符串的每个子字符串。在你告诉我之前有人问过这个问题之前,我想说的是,我看到的这个任务的几乎每个代码实现都不包含重复项。但是假设我有一个字符串“环境”,我想要每个子字符串,包括“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”等字符串,因为它们都是“environment”这个词的子字符串。为了实现这一点,我必须对我的功能进行哪些更改?

另外,由于我是一名 Java 初学者,我想知道我的代码是否写得好,以及我可以对我的代码进行哪些更改以使其性能和外观更好,并遵循常见的 Java 编码约定。

提前致谢

【问题讨论】:

  • 好吧,您可以编写一个算法来写入所有子字符串,然后您可以将它们全部反转并添加到您的列表中。
  • 但“十”并不完全是一个子字符串,尽管您可以通过重用字符串中出现的相同字母来获得这个词
  • @Leo“十”不是子串???那它叫什么?我如何将它添加到我的 arrayList 中?
  • 这是子串之一的排列
  • @Kaylo17 它之所以被称为“字符串”,是因为它是一个字母序列。所以我们可以说“ent”是“environment”的子串,但“ten”不是。如果您还想在给定“环境”之类的字符串的情况下获得诸如“十”之类的值,那么您正在寻找的(在我看来)是“环境”一词中出现的字母的排列

标签: java string


【解决方案1】:

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

2) 为每个子字符串生成它的所有排列 - 您可以使用位向量递归或迭代地执行此操作(此处已显示如何执行此操作,快速谷歌搜索也会给您一些提示)

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

例如使用“abc”你会得到:

  • 一个(1 个字符,1 个排列)
  • ab(子字符串)
    • ba(子串排列)
  • abc(子字符串)
    • bca(子串排列)
    • bac(子串排列)
    • acb(子串排列)
    • cab(子串排列)
    • cba(子串排列)

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

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

【讨论】:

  • 我认为这正是我正在寻找的。我会写出函数并发布它。我不担心时间复杂度和效率,因为这主要是为了学习目的
  • @Kaylo17 - 不要忘记消除所有重复项,可能通过将您的列表转换为 set 和返回。
  • @PM77-1 公平点,我的算法在这方面非常幼稚,因为他不介意时间复杂度,我想这不是问题。
  • @MateuszDymczyk 好吧,经过一番努力,我想出了这个程序。 pastebin.com/hzknuhac 。如果你有时间,你能告诉我如何改进它或使它更有效率。我还意识到,对于超过 9 个字母的单词,我会遇到内存不足异常
【解决方案2】:

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;
}

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

【讨论】:

  • 它比我创建的那个好很多。非常感谢。但是,当我输入超过 7 个字符时,它仍然会出现内存不足的异常。不过我会找到解决这个问题的方法。再次感谢。
  • 问题将出在如此大的字符串列表中。您可以传入消费者并在生成每个字符串时对其进行处理。一个有趣的任务是将这个任务分解为多个线程。
  • 这听起来很有趣。我会在接下来的几个小时内尝试并继续努力,看看我能想出什么
猜你喜欢
  • 1970-01-01
  • 2014-06-03
  • 2015-09-11
  • 2022-01-27
  • 2014-05-09
  • 2022-09-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多