繁体   English   中英

如何处理字谜搜索期间字符串排列的时间复杂度?

[英]How to handle the time complexity for permutation of strings during anagrams search?

我有一个程序可以计算两个字符串是否是字谜。 它适用于长度低于 10 的字符串输入。当我输入两个长度相等且长度超过 10 的字符串时,程序运行并且不产生答案。

我的概念是,如果两个字符串是字谜,一个字符串必须是另一个字符串的排列。

该程序从一个字符串生成所有排列,然后检查另一个字符串是否有任何匹配的排列。 在这种情况下,我想忽略案例。 当没有找到匹配的字符串或比较字符串的长度不相等时返回false,否则返回true。

public class Anagrams {
    static ArrayList<String> str = new ArrayList<>();

    static boolean isAnagram(String a, String b) {
        // there is no need for checking these two
        // strings because their length doesn't match
        if (a.length() != b.length())
            return false;

        Anagrams.permute(a, 0, a.length() - 1);

        for (String string : Anagrams.str)
            if (string.equalsIgnoreCase(b))
                // returns true if there is a matching string
                // for b in the permuted string list of a
                return true;
        // returns false if there is no matching string
        // for b in the permuted string list of a
        return false;
    }

    private static void permute(String str, int l, int r) {
        if (l == r)
            // adds the permuted strings to the ArrayList
            Anagrams.str.add(str);
        else {
            for (int i = l; i <= r; i++) {
                str = Anagrams.swap(str, l, i);
                Anagrams.permute(str, l + 1, r);
                str = Anagrams.swap(str, l, i);
            }
        }
    }

    public static String swap(String a, int i, int j) {
        char temp;
        char[] charArray = a.toCharArray();
        temp = charArray[i];
        charArray[i] = charArray[j];
        charArray[j] = temp;
        return String.valueOf(charArray);
    }
}

1.我想知道为什么这个程序不能处理更大的字符串

2.我想知道如何解决这个问题

你能弄清楚吗?

要解决此问题并检查两个字符串是否为字谜,您实际上并不需要生成源字符串的每个排列,然后将其与第二个排列进行匹配。 您可以做的是,计算第一个字符串中每个字符的频率,然后验证相同的频率是否适用于第二个字符串。

上面的解决方案需要对每个字符串进行一次传递,因此时间复杂度为 Θ(n)。 此外,您需要辅助存储来计算字符,这是 Θ(1) 空间复杂度。 这些是渐近紧的边界。

您正在以非常昂贵的方式进行操作,并且这里的时间复杂度是指数级的,因为您使用需要阶乘的排列并且阶乘增长非常快,因为您在进行排列时需要时间才能在输入更大时获得输出超过 10。

11 factorial = 39916800 12 factorial = 479001600 13 factorial = 6227020800

等等...

所以不要认为你没有得到大数字的输出,你最终会得到它

如果你使用 20-30 阶乘之类的东西,我想我将需要数年时间来产生任何输出,如果你使用循环,递归你会溢出堆栈。

事实: 50阶乘是一个比地球上沙粒的数量还要大的数字,当他们不得不处理那么大的数字时,计算机会屈服。

这就是为什么他们让你在密码中包含特殊字符以使得排列的数量太大,以至于如果他们尝试每个排列,计算机将无法破解它多年,而加密也取决于计算机的弱点。

所以你不必也不应该这样做来解决它(因为计算机不太擅长) ,这是一种矫枉过正

为什么不从一个字符串中取出每个字符并将其与其他字符串的每个字符匹配,在最坏的情况下它将是二次的。

如果你对两个字符串进行排序,那么你可以说

string1.equals(string2)

true意思是字谜

false意味着不是字谜

它将花费线性时间,除了排序所花费的时间。

您可以先从这些字符串中获取字符数组,然后sort它们进行sort ,然后比较两个排序后的数组。 此方法适用于常规字符代理对

public static void main(String[] args) {
    System.out.println(isAnagram("ABCD", "DCBA")); // true
    System.out.println(isAnagram("𝗔𝗕𝗖𝗗", "𝗗𝗖𝗕𝗔")); // true
}
static boolean isAnagram(String a, String b) {
    // invalid incoming data
    if (a == null || b == null
            || a.length() != b.length())
        return false;

    char[] aArr = a.toCharArray();
    char[] bArr = b.toCharArray();

    Arrays.sort(aArr);
    Arrays.sort(bArr);

    return Arrays.equals(aArr, bArr);
}

另请参阅:检查一个数组是否是另一个数组的子集 - 特殊情况

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM