我想用Dictionary<Dictionary<char,int>, List<string>>
实现一个算法来查找词典中的字谜词。
因为我需要为这个词典实现我的自定义EqualityComparer
,访问时间是否仍为O(1),即大O(1)?
第二个问题,作为EqualityComparer
的一部分,我还需要实现GetHashCode()
。确定GetHashCode()
Dictionary<Dictionary<char,int>, List<string>>
的有效方法是什么?
我刚想出了这种方法,还有更好的选择吗?
public int GetHashCode(Dictionary<char, int> obj)
{
unchecked
{
int hashCode = 17;
foreach (var item in obj)
{
hashCode += 23 * item.Key.GetHashCode();
}
return hashCode;
}
}
任何建议都表示赞赏。谢谢!
答案 0 :(得分:2)
如何将单词“need”转换为字符串“d1e2n1”而不是使用Dictionary作为键?为了构建此字符串,您可以使用二叉树。 char将用作键,字符计数为value。二叉树按键自动排序,而字典则不然。
您可以通过将二进制表示与XOR运算相结合来计算单个哈希值的组合哈希值。使用C#,您可以执行以下操作:
public override int GetHashCode()
{
// Combine hashcode of a and b
return a.GetHashCode() ^ b.GetHashCode();
}
在未排序列表中查找条目是O(n)操作。如果使用二进制搜索,则在排序列表中查找条目是O(log(n))操作。
在字典中的列表中查找单词是O(1 + n)操作,它与O(n)操作相同,或者是O(1 + log(n))操作,即与O(log(n))操作相同。
修改强>
这是一个可能的实现:
var anagrams = new Dictionary<string, List<string>>();
foreach (string word in words) {
string key = GetFrequency(word);
List<string> list;
if (anagrams.TryGetValue(key, out list)) {
list.Add(word);
} else {
list = new List<string> { word };
anagrams.Add(key, list);
}
}
它使用此方法获取密钥:
private string GetFrequency(string word)
{
var dict = new SortedDictionary<char, int>(); // Implemented as binary tree
foreach (char c in word.ToLower()) {
int count;
if (dict.TryGetValue(c, out count)) {
dict[c] += 1;
} else {
dict[c] = 1;
}
}
return dict.Aggregate(new StringBuilder(), (sb, item) => sb.Append(item.Key).Append(item.Value), sb => sb.ToString());
}
将这个定义用于单词......
var words = new List<string> { "need", "eden", "team", "meat", "meta", "Nat", "tan" };
这个测试...
foreach (var item in anagrams.OrderBy(x => x.Key)) {
Console.WriteLine();
Console.WriteLine(item.Key + ":");
foreach (string word in item.Value.OrderBy(w => w)) {
Console.WriteLine(" " + word);
}
}
...产生此输出
a1e1m1t1:
meat
meta
team
a1n1t1:
Nat
tan
d1e2n1:
eden
need
编辑#2:
这是Ben Voigt建议的频率计算
private string GetFrequencyByBenVoigt(string word)
{
char[] chars = word.ToLower().ToCharArray();
Array.Sort(chars);
return new string(chars);
}
测试结果将是
aemt:
meat
meta
team
ant:
Nat
tan
deen:
eden
need
答案 1 :(得分:2)
Dictionary<TKey, TValue>
的访问时间接近 O(1),但并非如此。在理想情况下(良好分布/少碰撞),您可以将其视为O(1)。在由于GetHashCode值的低差异而存在大量冲突的情况下,访问时间降低并且可以接近O(N)。
答案 2 :(得分:1)
基于容器内容的哈希码将是容器中项目数的O(n)
。您可以将字典包装在另一种类型中并缓存哈希代码,这样它只需要计算一次......但我可以想到几种比字典更有效的方法来存储数据。