我刚开始经历“破解编码面试”并针对此问题提供以下解决方案:
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解决了这个问题,但想要一个不涉及排序的附加解决方案。
这种方法可以变得更优雅吗?代码工作正常,我只是想知道是否有更优雅或更好的解决方案。谢谢!
答案 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)
t
t
中当前的s
字符是否存在,如果不存在,则它们不是字谜s
如果结果为空字符串,则为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()
。