【问题标题】:Anagram time complexity字谜时间复杂度
【发布时间】:2014-01-09 14:13:34
【问题描述】:

我正在尝试解决以下问题

给你两个字符串。大小为 n 的 A,大小为 m 的 B。 m是一个非常非常 与 n 相比,数字很小。找出 A 是否包含一个子字符串 是 B 的字谜。

我采取的方法如下

public static boolean ana_check(String a, String b)
{
    int n=a.length();
    int m=b.length();
    boolean k;
    for(int i=0;i<=(n-m);i++){
        k= anagram((a.substring(i,i+m)),b);
        if(k)
            return true;
}
    return false;
}

如你所见,我从字符串 A 的开头提取每个长度为 m 的字符串,并检查它是否是 B 的变位词。 为了检查字谜,我为每个字符串构建了一个频率图,如果发现它们相同,我返回 true。代码如下:

  public static boolean anagram(String s, String t) {
        // Strings of unequal lengths can't be anagrams
        if(s.length() != t.length()) {
            return false;
        }

        // They're anagrams if both produce the same 'frequency map'
        return frequencyMap(s).equals(frequencyMap(t));
    }

    private static Map<Character, Integer> frequencyMap(String str) {
        Map<Character, Integer> map = new HashMap<Character, Integer>();
        for(char c : str.toLowerCase().toCharArray()) {
            Integer frequency = map.get(c);
            map.put(c, frequency == null ? 1 : frequency+1);
        }
        return map;
    }

我相信 anagram 方法在 O(n) 时间运行。 ana_check 方法的时间复杂度是多少?整体代码是线性的还是二次的?

【问题讨论】:

    标签: string substring time-complexity anagram


    【解决方案1】:

    好吧,让我们看看...

    假设 length() 方法在恒定时间内运行(即:它不像 strlen() 那样工作)。 您的方法 frequencyMap 是 o(m),并且 anagram 调用它两次。 anagram 被称为 n-m 次。 总复杂度约为 o(2*m*n)。对于 m

    我可以提出一些优化建议。首先,您在每次调用 anagram 时重新生成字符串 b 的频率图。在 ana_check 开始时执行一次。你可以有一个 anagram 方法,它接受一个字符串和一个频率图而不是两个字符串。

    我要做的另一件事是从 anagram 中删除长度检查。是的,这是一项安全功能,但您已经知道传入的字符串大小相同。无论如何,如果它们的长度不同,频率图仍然不匹配,所以函数是正确的。

    更棘手的优化是修改字符串 a 的频率图,而不是每次都重新进行。对于第一个子字符串,您照常进行。但随后您向前移动一个字符,从地图中减去第一个字符并添加新字符。当然,如果 m

    【讨论】:

      【解决方案2】:

      您无需比较每个位置的整个地图。

      首先创建一个有符号频率图并减去每个字母 在B。保留一个计数器c 包含多少个非零条目 在地图中。

      接下来将A 的第一个mB 的长度)字母添加到地图中。为了 您添加的每个字母,如果该计数曾经为零,则增加c, 或者如果在您添加字母后它变为零,则减少 c

      如果 c 现在为零,那么您找到了一个字谜(每个负数 来自B 已被来自A 的正数平衡,否则 继续。

      A的下一个字母添加到频率图中,并删除该字母 m 之前的字母,为两者适当调整 c 操作。

      重复最后两个步骤,直到 c 变为零或您用完 A中的字母。

      您可以尝试通过认识到每次 你添加一个没有出现在B中的字符,你保证 下一个 m 字符不匹配(这与计数变为正数不同,因为您传递的其他字符可能会在 m 之前取消它)。所以你可以重启 在那封信之后的先决条件。操作的复杂性 但是,这允许您跳过不是很高,而且这种特殊情况 代码可能不会更快。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-04-15
        • 2022-08-12
        • 2020-07-07
        • 2016-02-13
        • 2012-08-14
        • 1970-01-01
        • 1970-01-01
        • 2018-10-23
        相关资源
        最近更新 更多