给出两个字符串,一个是另一个的字谜

时间:2013-04-22 07:30:25

标签: c#

我刚开始经历“破解编码面试”并针对此问题提供以下解决方案:

public static bool isAnagram(String s, String t)
{
    if (s == "" || t == "") return false;
    else if (s.Length != t.Length) return false;

    int[] letters = new int[256];
    char[] s_array = s.ToCharArray();

    foreach(char c in s_array) 
    { 
        letters[c]++;  
    }

    for (int i = 0; i < t.Length; i++)
    {
        int c = t[i];
        if (--letters[c] < 0) 
        {
            return false;
        }
    }
    return true;
}

这几乎是本书的逐字解决方案,仅限于C#,而不是Java,还有一些额外的nullcheck。我还使用LINQ解决了这个问题,但想要一个不涉及排序的附加解决方案。

这种方法可以变得更优雅吗?代码工作正常,我只是想知道是否有更优雅或更好的解决方案。谢谢!

8 个答案:

答案 0 :(得分:16)

此代码适用于您:

public static bool IsAnagram(string s1, string s2)
{
    if (string.IsNullOrEmpty(s1) || string.IsNullOrEmpty(s2))
        return false;
    if (s1.Length != s2.Length)
        return false;

    foreach (char c in s2)
    {
        int ix = s1.IndexOf(c);
        if (ix >= 0)
            s1 = s1.Remove(ix, 1);
        else
            return false;
    }

    return string.IsNullOrEmpty(s1);
}

编辑:添加了非linq版本。

您还可以为null和empty值添加一些额外的检查,并将解决方案移到StringBuilder以提高性能,但代码的意图很明确。

答案 1 :(得分:4)

正如您要求更优雅的解决方案,也许这个可以满足您的需求 - 更加紧凑,作为扩展方法编写:

public static bool IsAnagram(this string s1, string s2)
{
    if (s1.Length == s2.Length)
    {
        var count = new int[1024];
        foreach (var c in s1)
        {
            ++count[c];
        }
        return s2.All(t => --count[c] >= 0);
    }
    return false;
}

var result = "mary".IsAnagram("army");

答案 2 :(得分:3)

要正确处理所有Unicode字符(因为Char代表UTF-16代码单元),我想不出有效的方法。但我会尝试使用正确的

public static bool isAnagram(String s, String t)
{
    s = s.Normalize();
    t = t.Normalize();

    if (s == "" || t == "") return false;
    else if (s.Length != t.Length) return false;

    while (s.Length > 0)
    {
        char first = s[0];
        string search = new string(first, 1);
        if (Char.IsHighSurrogate(first))
        {
            char second = s[1]; //Assumed to work - if it doesn't, the input was malformed
            search = new string(new char[] { first, second });
        }
        int index = t.IndexOf(search);
        if (index < 0) return false;
        t = (index > 0 ? t.Substring(0, index) : "") + t.Substring(index + search.Length);
        s = s.Substring(search.Length);
    }
    return true;
}

否则,如果你想继续使用一组计数器(letters),你应该使用一个至少包含1114112个元素的数组,你仍然需要正确处理代理。

答案 3 :(得分:2)

您可以对两个字符串进行排序并进行比较

答案 4 :(得分:2)

这个非linq解决方案怎么样?

public static bool IsAnagram(String s, String t)
{
    if ((s == null) || (t == null) || (s.Length == 0) || (t.Length == 0) || (s.Length != t.Length))
        return false;

    var ta = t.ToCharArray();

    foreach (char ch in s)
    {
        int x = Array.IndexOf(ta, ch);

        if (x < 0)
            return false;

        ta[x] = '\0';
    }

    return true;
}

答案 5 :(得分:1)

基于字典的解决方案。通过计算char来分解每个字符串,然后执行Dictionary comparaison(注意这种方法让我大吃一惊):

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("jon skeet".PermutationOf("jokes net"));
        Console.WriteLine(new[] { 5, 2, 3, 4, 5 }.PermutationOf(new[] { 5, 4, 5, 2, 3 }));
        Console.Read();
    }
}

public static class Extensions
{
    public static bool IsPermutationOf<T>(this IEnumerable<T> source1, IEnumerable<T> source2)
    {
        return source1.IsPermutationOf(source2, EqualityComparer<T>.Default);
    }
    public static bool IsPermutationOf<T>(this IEnumerable<T> source1, IEnumerable<T> source2, EqualityComparer<T> comparer)
    {
        return source1.Decompose(comparer).DictionaryEqual(source2.Decompose(comparer));
    }
    public static Dictionary<T, int> Decompose<T>(this IEnumerable<T> source, EqualityComparer<T> comparer)
    {
        return source.GroupBy(t => t, comparer).ToDictionary(t => t.Key, t => t.Count(), comparer);
    }
    public static bool DictionaryEqual<TKey, TValue>(this IDictionary<TKey, TValue> first, IDictionary<TKey, TValue> second)
    {
        return first.Count == second.Count && !first.Except(second).Any();
    }
}

请注意,您可以提供自定义char相等比较器,以处理大写/小写问题。

我更进一步,通过IsAnagram重命名IsPermutationOf。事实上适用于各种列表。这样非常有用和优雅。

答案 6 :(得分:1)

  1. 检查长度是否相等,如果不相等,则它们不是anagram
  2. 循环遍历t
  3. 的字符
  4. 检查t中当前的s字符是否存在,如果不存在,则它们不是字谜
  5. 如果是,请从s
  6. 中删除该字符
  7. 如果结果为空字符串,则为anagram

    public static bool isAnagram(String s, String t) {
        if(s.Length != t.Length) 
            return false;
    
        for(int i = 0; i < t.Length; i++)
        {
            var n = s.IndexOf(t[i]);
            if(n < 0)
                return false;
            s = s.Remove(n, 1);
        }
        return String.IsNullOrEmpty(s);
    }
    

答案 7 :(得分:0)

排序然后比较序列的工作原理:

bool isAnagram = "asdf".OrderBy(c => c).SequenceEqual("fdsa".OrderBy(c => c));

或者,您可以使用Dictionary<char, int>来跟踪字符数(Unicode字符有超过256个可能的值)。此外,在迭代字符串的字符之前,您不需要调用ToArray()