【问题标题】:How do I find the decomposition of a string?如何找到字符串的分解?
【发布时间】:2020-08-10 08:50:02
【问题描述】:

我需要为String 分解创建一个算法。

一些例子:

  • ABCABCDEDEDEF --> ABC*2+DE*3+F
  • ABCcABCczcz --> ABC*2+cz*2+c
  • test --> test

字符串的每个部分都应该用+ 分隔,如果重复,后面跟着* 加上它连续出现的次数。

这是我尝试过的:

private static int[] prefixFunction(String source) {
    int n = source.length();
    int[] pi = new int[n];

    for (int i = 1; i < n; i++) {
        int j = pi[i - 1];

        while (j > 0 && source.charAt(i) != source.charAt(j))
            j = pi[j - 1];

        if (source.charAt(i) == source.charAt(j))
            j++;

        pi[i] = j;
    }

    return pi;
}

【问题讨论】:

  • 嵌套好吗?即(ABC * 2 + DEF)* 3
  • 我认为不,因为在这个问题中,我需要在不带任何括号的字符串上仅使用+* 操作来构建最经济的输入字符串表示。
  • “占用最少空间”是什么意思?字符串是否总是像 DEABC 等这样连续?一些额外的例子会很好。
  • @Daniel “占用最少空间” = 最佳解决方案。另外,添加其他示例。
  • @SlandShow - 我觉得还是有问题,你知道ABCcABCczcz有11个字符而ABC*2+cz*2+c有12个字符,这与test基本相同,修改为不值得。

标签: java string algorithm


【解决方案1】:

这可以通过使用 KMP alogorthm 最长前缀(也是后缀)来解决 步骤:

  1. 迭代字符串“ABCABCDEDEDEF”并为该字符串构造 lps 数组。数组中的值将是 0 0 0 1 2 3 0 0 0 0 0 0 0 这个 lps 数组给出了前缀在字符串中重复的次数。 在上述情况下,它只重复一次。考虑到实际的前缀次数是 2,它变成了 ABC*2
  2. 取出剩余字符串的子字符串,重复步骤1直到字符串结束。

如果需要,我可以为您提供代码。最坏的时间复杂度将是 O(n2)

【讨论】:

    【解决方案2】:

    此解决方案使一切井井有条,这意味着像ABCABCDEDEDEF 这样的输入将返回ABC*2+DE*3+F,或者像abDEDEab 这样的输入将返回ab+DE*2+ab

    如果您不遵守订单,以后将无法以 100 % 的准确率重建 String

    public static void main(String[] args) {
        String input = "ABCABCDEDEDEF";
    
        String output = findDecomposition(input);
        System.out.println("Output: " + output);
    }
    
    public static String findDecomposition(String input) {
        String substring = input;
        StringBuilder builder = new StringBuilder();
    
        for (int start = 0, count = 1; start < input.length(); start++, count = 1) {
            for (int end = start + 1; end < input.length(); end++) {
                substring = input.substring(start, end);
    
                while (true) {
                    String next = input.substring(start + substring.length(), Math.min(end + substring.length(), input.length()));
    
                    if (next.equals(substring)) {
                        count++;
                        start += substring.length();
                        end += substring.length();
                    } else
                        break;
                }
    
                if (count > 1) {
                    start += substring.length() - 1;
                    break;
                }
            }
    
            if (count > 1) {
                if (builder.length() > 0 && builder.charAt(builder.length() - 1) != '+')
                    builder.append('+');
    
                builder.append(substring + "*" + count + "+");
            } else
                builder.append(input.charAt(start));
        }
    
        String result = builder.toString();
        if (result.endsWith("+"))
            return result.substring(0, result.length() - 1);
        else
            return result;
    }
    

    【讨论】:

    • 快速阅读后感觉就像我在想的一样:滑动窗口方法可能是保持顺序的唯一方法。 +1
    • 能够以 100% 的准确度重建字符串并不是规定的要求之一,使用此约束可能会导致与未解决此约束的方法大不相同的结果。
    • @גלעדברקן 没错。但是,无论如何,我还是想指出这种方法的优势。另外,我知道这种方法的结果与其他方法不同。如果 OP 不想保留订单,他们可以选择另一个答案。
    • abDEDE 是一个比ab+DE*2 更短的字符串,更不用说整个示例会更短为一个块。
    • @גלעדברקן 是的,该问题已在问题下的 cmets 中直接说明,并且通常适用于整个系统。仍然可能有其他原因 OP 需要它,我刚刚提供了一个有效的答案。
    【解决方案3】:

    此代码返回以下组合:

    • ABCABCDEDEDEF -&gt; ABC*2+DE*3+F
    • ABCcABCczcz -&gt; ABCc*2+zcz
    • cefABCcABCczcz -&gt; cef+ABCc*2+zcz
    
    
        import java.util.ArrayList;
        import java.util.Collections;
        import java.util.Comparator;
        import java.util.List;
        import java.util.stream.Collectors;
    
        public class Decomposition {
    
    
            public static void main(String[] args) {
                Decomposition d = new Decomposition("ABCABCDEDEDEF");
                System.out.println(d.getOptimalDecomposition());// Output: ABC*2+DE*3+F
    
                d = new Decomposition("ABCcABCczcz");
                System.out.println(d.getOptimalDecomposition());// Output: ABCc*2+zcz
    
                d = new Decomposition("cefABCcABCczcz");
                System.out.println(d.getOptimalDecomposition());// Output: cef+ABCc*2+zcz
            }
    
    
    
            private List> decompositions;
            private String toDecompose;
    
            public Decomposition(String toDecompose) {
                decompositions = new ArrayList();
                this.toDecompose = toDecompose;
            }
    
            public String getOptimalDecomposition() {
    
                decompose(0, new ArrayList());
    
                return calculateOptimal(convertToPartsMap());
            }
    
            private String calculateOptimal(List> partsCount) {
                Collections.sort(partsCount, new SortDecompositions());
    
                StringBuilder optimal = new StringBuilder();
    
                for (int i = 0; i  1) {
                        optimal.append("*");
                        optimal.append(pc.count);
                    }
    
                    if (i != partsCount.get(0).size() - 1) {
                        optimal.append("+");
                    }
                }
    
                return optimal.toString();
            }
    
            private List> convertToPartsMap() {
                List> partsMap = new ArrayList();
    
                for (List parts : decompositions) {
                    List partsCount = new ArrayList();
    
                    String lastPart = null;
                    int curCount = 0;
    
                    for (int i = 0; i  parts) {
    
                if (nextChar == toDecompose.length()) {
                    decompositions.add(parts);
                    return;
                }
    
                char toAdd = toDecompose.charAt(nextChar);
    
                if (parts.isEmpty()) {
                    parts.add("" + toAdd);
                    decompose(nextChar + 1, parts);
                } else {
    
                    // left
                    List leftParts = parts.stream().collect(Collectors.toList());// shallow copy
                    if (!leftParts.isEmpty()) {
                        int last = leftParts.size() - 1;
                        leftParts.set(last, leftParts.get(last) + toAdd);
                    } else {
                        leftParts.add("" + toAdd);
                    }
    
                    // right
                    List rightParts = parts.stream().collect(Collectors.toList());// shallow copy
                    rightParts.add("" + toAdd);
    
                    decompose(nextChar + 1, leftParts);
                    decompose(nextChar + 1, rightParts);
                }
            }
    
        }
    
        class PartCount {
            String part;
            int count;
    
            public PartCount(String part, int count) {
                this.part = part;
                this.count = count;
            }
    
            @Override
            public String toString() {
                return "[" + part + ", " + count + "]";
            }
        }
    
        class SortDecompositions implements Comparator> {
    
            public int compare(List a, List b) {
                // Here you can define what exactly means "taking up least space".
                return countChars(a) - countChars(b);
            }
    
            private int countChars(List listPc) {
                int count = 0;
                for (PartCount pc : listPc) {
                    count += pc.part.length();
                }
                return count;
            }
        }
    
    

    【讨论】:

      【解决方案4】:

      蛮力算法可以如下工作。

      先决条件:

      • 第一个字母设置为root
      • 每个可能解决方案的数据结构都是链表。每个节点的值是要写入的文本。
      • 输出解决方案时,首先将所有文本值与出现次数一起映射。如果出现多次,请使用* 作为乘数

      示例:其中一个解决方案看起来像这样ABC-C-ABC,输出将是ABC*2+C

      解决方案:

      1. 从输入中取出下一个字母
      2. 新解决方案基于现有解决方案。每个新解决方案都是旧解决方案 + 在现有节点之一中添加的新字母或作为新节点中的单个字母。
      3. 将新解决方案另存为现有解决方案。
      4. 从 1 开始重复,直到处理完所有字母
      5. 计算所有解的值并选择字符串字符最少的解

      我添加了示例,您可以看到解决方案的数量正在迅速增加,因此所有 6 个字母都没有完全完成。每个步骤代表从 1. 到 4. 的循环,您可以看到在每个步骤中,以前的解决方案都用作新解决方案的基础。为每个现有解决方案创建了多个新解决方案。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-03-03
        • 2020-02-12
        • 2013-11-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-07-22
        相关资源
        最近更新 更多