【问题标题】:check whether a string C is an interleaving of A and B检查字符串 C 是否是 A 和 B 的交错
【发布时间】:2013-09-10 22:04:25
【问题描述】:

给定三个字符串 A、B 和 C。编写一个函数,检查 C 是否是 A 和 B 的交织。如果 C 包含 A 和 B 的所有字符以及所有字符的顺序,则称 C 是交织 A 和 B单个字符串中的字符被保留。

例如:

  • 'hotdog' 是 'hot' 和 'dog' 的交错(简单)
  • “superb”是“up”和“serb”的交织
  • “heartache”是“ear”和“ache”的交织
  • 'chat' 是 'hat' 和 'cat' 的交织
  • 'cheaters' 不是 'chat' 和 'seer' 的交错,因为虽然它包含来自每个人的所有字母,但来自 'seer' 的字母并没有按顺序出现

我在 net 中找到了一些解决方案,但下面是我的方法,有人可以告诉我我是否遗漏了什么或 我的算法会起作用吗?谢谢。

我的算法:

  1. 遍历ac。在遍历时,我们首先计算两件事:char 是否存在并保存索引,即找到 char 的f。一旦我们找到这个字符,我们应该在那个地方放一些特殊的字符,这样我们就不会再考虑这个字符了。
  2. 对于a 中的下一个字符,从您找到前一个字符的索引中搜索c,即f。如果我们没有找到,则返回。
  3. b 也是如此。
  4. 如果在执行上述步骤后,如果我们找到false,而不是重复第一个b 而不是a,并返回结果。

例如

a = xxy, b = xxz and c = xxzxxxy

以:开始

  1. 对于 a 中的 x,c = 0xzxxxy(我将 0 作为特殊字符)
  2. 对于 a 中的 x,从索引 0 开始(因为我们在 0 处找到了前一个字符)c = 00zxxxy。
  3. 对于 a 中的 y,c = 00zxxx0
  4. 对于 b 中的 x,c = 00z0xx0
  5. 对于 b 中的 x,c = 00z00x0
  6. 对于 b 中的 z,我们在索引 4 之后找不到 z,这是我们找到 b 的前一个字符的索引。

因为以 a 开头返回 false,所以我们现在将从 b 开始。

所以从 b 开始:

  1. 对于 b 中的 x,c = 0xzxxxy
  2. 对于 b 中的 x,c = 00zxxxy
  3. 对于 b 中的 z,c = 000xxxy
  4. 对于 a 中的 x,c = 0000xxy
  5. 对于 a 中的 x,c = 00000xy
  6. 对于 a 中的 y,c = 00000x0

因此 true i.e.c 是 a 和 b 的交错字符串。

【问题讨论】:

  • 我怀疑这是一个比一开始听起来更复杂的问题,因为您很容易走错路而不得不回溯。
  • 这可以随心所欲吗?还是您必须满足复杂性要求?
  • @Cruncher 上面的解决方案是 O(N^2)。您可以对上述算法发表意见,也可以自己发表意见。
  • @Trying:为什么要删除链接?我认为 DP 解决方案是您能找到的最佳解决方案之一。
  • @nhahtdh 你想让我恢复它吗?我想在这里重新尝试解决方案。

标签: java string algorithm


【解决方案1】:

您的解决方案代表一个稍作修改的greedy algorithm,因为它在第一次发现时将C 中的字符视为属于A(或在第二次通过时属于B)一场比赛。这将中断以下字符串:

A = xxyxxy
B = xxzxxz
C = xxzxxyxxyxxz

将匹配字符计为A 成员的第一遍将把C 变成

00zxx0000xxz

将匹配字符计为B 成员的第二遍将把C 变成

00000yxxyxx0

这是memoized 解决方案的简单Java 实现:

private static boolean checkOverlap(String a, String b, String c) {
    Boolean[][][] memoize = new Boolean[a.length()+1][b.length()+1][c.length()+1];
    return checkOverlap(a, b, c, 0, 0, 0, memoize);
}
private static boolean checkOverlap(
    String a
,   String b
,   String c
,   int pa
,   int pb
,   int pc
,   Boolean[][][] memoize
) {
    Boolean res = memoize[pa][pb][pc];
    if (res != null) {
        return (boolean)res;
    }
    if (pa == a.length() && pb == b.length() && pc == c.length()) {
        res = true;
    } else if (pc == c.length()) {
        res = false;
    } else {
        res = false;
        if (pa != a.length() && c.charAt(pc) == a.charAt(pa) && checkOverlap(a, b, c, pa+1, pb, pc+1, memoize)) {
            res = true;
        } else if (pb != b.length() && c.charAt(pc) == b.charAt(pb) && checkOverlap(a, b, c, pa, pb+1, pc+1, memoize)) {
            res = true;
        }
    }
    return (memoize[pa][pb][pc] = res);
}

Demo on ideone.

【讨论】:

  • 你能推荐一个,可能很有效。谢谢。
  • @Trying 基于DP的方案(第二个)from the site that you referenced before the edit效率很高。您还可以通过应用memoization 将第一个解决方案(递归解决方案)转换为有效的解决方案。
  • 我点击了链接,但我无法在递归方法中找到重叠的子问题,以便我可以使用记忆。请帮助我至少找到子问题,从中我可以感觉到。谢谢。
  • @Trying 我从您的链接中添加了记忆递归解决方案的 Java 实现 - 看看。
  • @Trying 我想we can,但我很难证明这一点。
【解决方案2】:

首先,我会检查 A 的长度和 B 的长度之和是否等于 C 的长度。

接下来,检查A的第一个字符是否等于C的第一个字符。

如果不是,检查B的第一个字符是否等于C的第一个字符。

检查以 A 或 B 开头的其他字符,具体取决于上述两个条件中的哪一个为真。

这是一个可以进行测试的方法:

public boolean isInterleaved(String a, String b, String c) {
    int aIndex = 0;
    int bIndex = 0;
    int cIndex = 0;
    while (cIndex < c.length()) {
        if (aIndex < a.length()) {
            if (a.charAt(aIndex) != c.charAt(cIndex)) { return false; }
            cIndex++;
            aIndex++;
        }
        if (bIndex < b.length()) { 
            if (b.charAt(bIndex) != c.charAt(cIndex)) { return false; }
            cIndex++;
            bIndex++;
        }
    }

    return true;
}

您最多会调用此方法两次。电话将是

if (isInterleaved(a, b, c))

if (isInterleaved(b, a, c))

如果 A 的第一个字符和 B 的第一个字符相等,请检查以您在上一步中未开始的 A 或 B 字符串开头的其他字符。

这样,你就省去了对可能满足条件的字符串的复杂测试。

【讨论】:

  • 感谢您的评论。我可以进行上述所有优化,但你能告诉我我上面的方法是否会给我正确的结果吗?谢谢。
  • @Trying:我只是对 C 字符做一个简单的循环。请参阅我编辑的答案。
  • 我的索引超出范围:isInterleaved("xxxy", "xx", "xxxxxy"),它为isInterleaved("x", "xx", "x")返回true
  • @Trying:我忘记了 A 和 B 字符串的长度可能不同。请参阅我编辑的答案。在调用此方法之前,您还应该进行我概述的其他测试。
  • 检查:字符串 A = "xxyxxy";字符串 B = "xxzxxz";字符串 C = "xxzxxyxxyxxz";答案应该是正确的,但您的代码将返回错误。
【解决方案3】:
def isinterleave(a, b, c):
   la = len(a)
   lb = len(b)
   lc = len(c)
   if la + lb != lc: return False
   if la == lb == lc == 0: return True
   if (la > 0 and lb >0 and a[0] == b[0] == c[0]):
     return isinterleave(a[1:], b, c[1:]) or isinterleave(a, b[1:], c[1:])
   if (la > 0 and a[0] == c[0]):
     return isinterleave(a[1:], b, c[1:])
   if (lb > 0 and b[0] == c[0]):
     return isinterleave(a, b[1:], c[1:])
   return False

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-01
    • 2013-11-22
    • 1970-01-01
    • 1970-01-01
    • 2012-06-27
    相关资源
    最近更新 更多