测试字符串中重复的字符

我正在用字符串做一些工作,我有一个场景,我需要确定一个字符串(通常是一个小的<10个字符)是否包含重复的字符。

`ABCDE` // does not contain repeats `AABCD` // does contain repeats, ie A is repeated 

我可以循环遍历string.ToCharArray()并测试char []中每个其他角色的每个角色,但我觉得我错过了一些明显的东西….也许我只需要咖啡。 有人可以帮忙吗?

编辑:

字符串将被排序,因此顺序并不重要,因此ABCDA => AABCD

重复的频率也很重要,所以我需要知道重复是双重还是三重等。

如果字符串很短,那么只需循环和测试可能是最简单和最有效的方法。 我的意思是你可以创建一个哈希集(在你正在使用的任何平台上)并迭代字符,如果字符已经在集合中并且将其添加到集合中则失败 – 但是这只能提供任何好处字符串更长。

编辑:现在我们知道它的排序, mquander的答案是最好的一个IMO。 这是一个实现:

 public static bool IsSortedNoRepeats(string text) { if (text.Length == 0) { return true; } char current = text[0]; for (int i=1; i < text.Length; i++) { char next = text[i]; if (next <= current) { return false; } current = next; } return true; } 

如果您不介意重复使用索引器,则可以选择较短的替代方法:

 public static bool IsSortedNoRepeats(string text) { for (int i=1; i < text.Length; i++) { if (text[i] <= text[i-1]) { return false; } } return true; } 

编辑:好的,有了“频率”方面,我会把问题转过来。 我仍然会假设字符串已经排序,所以我们想知道的是最长运行的长度。 当没有重复时,最长的运行长度将为0(对于空字符串)或1(对于非空字符串)。 否则,它将是2或更多。

首先是特定于字符串的版本:

 public static int LongestRun(string text) { if (text.Length == 0) { return 0; } char current = text[0]; int currentRun = 1; int bestRun = 0; for (int i=1; i < text.Length; i++) { if (current != text[i]) { bestRun = Math.Max(currentRun, bestRun); currentRun = 0; current = text[i]; } currentRun++; } // It's possible that the final run is the best one return Math.Max(currentRun, bestRun); } 

现在我们也可以将其作为IEnumerable的一般扩展方法:

 public static int LongestRun(this IEnumerable source) { bool first = true; T current = default(T); int currentRun = 0; int bestRun = 0; foreach (T element in source) { if (first || !EqualityComparer.Default(element, current)) { first = false; bestRun = Math.Max(currentRun, bestRun); currentRun = 0; current = element; } } // It's possible that the final run is the best one return Math.Max(currentRun, bestRun); } 

然后你可以调用"AABCD".LongestRun()作为例子。

如果字符串已排序,您可以依次记住每个字符并检查以确保下一个字符永远不会与最后一个字符相同。

除此之外,对于十个字符以下的字符串,只需针对所有其他字符测试每个字符,可能与大多数其他事物一样快或快。 另一位评论者建议的位向量可能更快(如果您有一小组合法字符,则会有所帮助。)

Bonus:这是一个实现Jonfunction的灵活的LINQ解决方案:

 int longestRun = s.Select((c, i) => s.Substring(i).TakeWhile(x => x == c).Count()).Max(); 

所以,好吧,它不是很快! 你对此有看法?!

🙂

如果字符串包含重复项,这将告诉您:

 bool containsDups = "ABCDEA".Length != s.Distinct().Count(); 

它只是根据原始长度检查不同字符的数量。 如果它们不同,你就有重复……

编辑:我想这并没有考虑你在编辑中注意到的重复频率…但是这里的一些其他建议已经解决了这个问题,因此我不会发布代码,因为我注意到它们中的一些已经给你一个相当优雅的解决方案。 我特别喜欢Joe使用LINQ扩展的实现。

由于您使用的是3.5,因此可以在一个LINQ查询中执行此操作:

 var results = stringInput .ToCharArray() // not actually needed, I've left it here to show what's actually happening .GroupBy(c=>c) .Where(g=>g.Count()>1) .Select(g=>new {Letter=g.First(),Count=g.Count()}) ; 

对于在输入中出现多次的每个字符,这将为您提供字符和出现次数。

我认为最简单的方法是使用这个简单的正则表达式

 bool foundMatch = false; foundMatch = Regex.IsMatch(yourString, @"(\w)\1"); 

如果您需要有关比赛的更多信息(开始,长度等)

  Match match = null; string testString = "ABCDE AABCD"; match = Regex.Match(testString, @"(\w)\1+?"); if (match.Success) { string matchText = match.Value; // AA int matchIndnex = match.Index; // 6 int matchLength = match.Length; // 2 } 

立即更新 ,您需要一组计数器来维护计数。

保持一个位数组,一位代表一个独特的字符。 遇到角色时打开它,然后在字符串上运行一次。 位数组索引和字符集的映射由您决定。 如果您已经看到特定位已打开,请中断。

怎么样的:

 string strString = "AA BRA KA DABRA"; var grp = from c in strString.ToCharArray() group c by c into m select new { Key = m.Key, Count = m.Count() }; foreach (var item in grp) { Console.WriteLine( string.Format("Character:{0} Appears {1} times", item.Key.ToString(), item.Count)); } 
 /(.).*\1/ 

(或者你的正则表达式库的语法中的等价物)

不是最有效的,因为它可能会回溯到字符串中的每个字符,然后再次向前扫描。 我通常不提倡正则表达式。 但如果你想要简洁……

我开始在网上寻找一些信息,我得到了以下解决方案。

 string input = "aaaaabbcbbbcccddefgg"; char[] chars = input.ToCharArray(); Dictionary dictionary = new Dictionary(); foreach (char c in chars) { if (!dictionary.ContainsKey(c)) { dictionary[c] = 1; // } else { dictionary[c]++; } } foreach (KeyValuePair combo in dictionary) { if (combo.Value > 1) //If the vale of the key is greater than 1 it means the letter is repeated { Console.WriteLine("Letter " + combo.Key + " " + "is repeated " + combo.Value.ToString() + " times"); } } 

我希望它有所帮助,我接受了一次面试,面试官要求我解决这个问题,我理解这是一个常见的问题。

如果没有订单可以使用,您可以使用字典来保持计数:

 String input = "AABCD"; var result = new Dictionary(26); var chars = input.ToCharArray(); foreach (var c in chars) { if (!result.ContainsKey(c)) { result[c] = 0; // initialize the counter in the result } result[c]++; } foreach (var charCombo in result) { Console.WriteLine("{0}: {1}",charCombo.Key, charCombo.Value); } 

Jon描述的哈希解决方案可能是最好的。 您可以使用HybridDictionary,因为它适用于小型和大型数据集。 字母是关键,值是频率。 (每次添加失败时更新频率,或者HybridDictionary为.Contains(key)返回true)