这是一个采访问题 - 如何使用单个字符有效地修剪字符串中的重复字符。
实施例: 假设这是输入字符串
" reeeturrrnneedd"
输出应为:
"返回"
我通过使用分割字符串并循环遍历char数组来解释它,但是访问者不相信答案说这不是有效的方法。
private void test()
{
string s = "reeeturrrnneeddryyf";
StringBuilder sb = new StringBuilder();
char pRvChar = default(char);
foreach (var item in s.ToCharArray())
{
if (pRvChar == item)
{
continue;
}
pRvChar = item;
sb.Append(pRvChar);
}
MessageBox.Show(sb.ToString());
}
然后我想到Linq要反对并使用distinct但它会输出不正确的输出,因为它删除了所有重复的字符,输出将是" retund"
有人可以告诉我更有效的方法吗?
答案 0 :(得分:6)
以下是正则表达式的解决方案:
Regex regex = new Regex( "(.)\\1+" );
string result = regex.Replace( s,"$1" );
我不确定,如果这样做更有效率,那么你的' for'在执行时间方面循环,但在开发人员工作方面更有效。 并且易于阅读,至少对熟悉正则表达式的人来说。
答案 1 :(得分:4)
如果您
,您当前的解决方案可能会更加优化预先分配StringBuilder
的容量,这在您的情况下是可能的,因为结果字符串与输入字符串的长度最多相同:
StringBuilder sb = new StringBuilder(s.Length);
避免构造一个char数组来迭代。 string
类会实现IEnumerable<char>
,因此您可以直接将其反馈给foreach
:
foreach (var item in s)
答案 2 :(得分:4)
以下是使用fixed
和unsafe
预分配结果的指针版本
unsafe string Mine()
{
var temp = string.Copy(Input);
var i = 0;
fixed (char* pInput = Input, pTemp = temp)
{
var plen = pInput + Input.Length;
for (var pI = pInput + 1; pI < plen; pI++)
if (*pI != *(pTemp+i))
*(pTemp + ++i) = *pI;
}
return temp.Substring(0,i+1);
}
Mode : Release
Test Framework : .NET Framework 4.7.1
Benchmarks runs : 100 times (averaged)
长度:100
Name | Average | Fastest | StDv | Cycles | Pass
---------------------------------------------------------
Mine | 0.003 ms | 0.002 ms | 0.00 | 3,935 | Yes
Dmitry | 0.003 ms | 0.002 ms | 0.00 | 5,455 | Yes
Billy | 0.003 ms | 0.002 ms | 0.00 | 5,706 | Yes
SAkbari3 | 0.007 ms | 0.006 ms | 0.00 | 19,730 | Yes
SAkbari1 | 0.009 ms | 0.008 ms | 0.00 | 25,029 | Yes
Original | 0.009 ms | 0.003 ms | 0.05 | 7,349 | Base
SAkbari2 | 0.014 ms | 0.011 ms | 0.00 | 41,027 | Yes
Heinz | 0.040 ms | 0.037 ms | 0.00 | 131,196 | Yes
长度:1,000
Name | Average | Fastest | StDv | Cycles | Pass
-----------------------------------------------------------
Mine | 0.005 ms | 0.004 ms | 0.00 | 11,126 | Yes
Billy | 0.008 ms | 0.007 ms | 0.00 | 22,402 | Yes
Dmitry | 0.009 ms | 0.006 ms | 0.00 | 24,487 | Yes
Original | 0.010 ms | 0.008 ms | 0.00 | 27,334 | Base
SAkbari3 | 0.041 ms | 0.040 ms | 0.00 | 136,272 | Yes
SAkbari1 | 0.075 ms | 0.049 ms | 0.05 | 231,981 | Yes
SAkbari2 | 0.101 ms | 0.076 ms | 0.03 | 334,375 | Yes
Heinz | 0.344 ms | 0.267 ms | 0.07 | 1,154,860 | Yes
长度:10,000
Name | Average | Fastest | StDv | Cycles | Pass
------------------------------------------------------------
Mine | 0.020 ms | 0.017 ms | 0.00 | 62,571 | Yes
Dmitry | 0.056 ms | 0.046 ms | 0.01 | 185,538 | Yes
Billy | 0.061 ms | 0.058 ms | 0.00 | 202,931 | Yes
Original | 0.069 ms | 0.058 ms | 0.01 | 230,297 | Base
SAkbari3 | 0.419 ms | 0.372 ms | 0.09 | 1,418,448 | Yes
SAkbari1 | 0.535 ms | 0.452 ms | 0.09 | 1,813,644 | Yes
SAkbari2 | 0.957 ms | 0.726 ms | 0.19 | 3,226,844 | Yes
Heinz | 2.951 ms | 2.574 ms | 0.47 | 10,027,205 | Yes
长度:100,000
Name | Average | Fastest | StDv | Cycles | Pass
--------------------------------------------------------------
Mine | 0.164 ms | 0.158 ms | 0.01 | 552,166 | Yes
Dmitry | 0.498 ms | 0.467 ms | 0.02 | 1,690,471 | Yes
Original | 0.561 ms | 0.523 ms | 0.06 | 1,894,019 | Base
Billy | 0.576 ms | 0.536 ms | 0.04 | 1,955,072 | Yes
SAkbari3 | 3.684 ms | 3.429 ms | 0.15 | 12,534,942 | Yes
SAkbari1 | 4.547 ms | 4.084 ms | 0.47 | 15,468,091 | Yes
SAkbari2 | 7.315 ms | 6.848 ms | 0.30 | 24,888,849 | Yes
Heinz | 26.091 ms | 24.898 ms | 1.17 | 88,905,648 | Yes
长度:1,000,000
Name | Average | Fastest | StDv | Cycles | Pass
-----------------------------------------------------------------
Mine | 1.841 ms | 1.549 ms | 0.20 | 6,256,290 | Yes
Dmitry | 5.237 ms | 4.740 ms | 0.27 | 17,808,335 | Yes
Original | 5.705 ms | 5.178 ms | 0.31 | 19,411,876 | Base
Billy | 6.027 ms | 5.374 ms | 0.31 | 20,477,533 | Yes
SAkbari3 | 39.369 ms | 36.608 ms | 2.27 | 134,030,971 | Yes
SAkbari1 | 46.502 ms | 44.410 ms | 1.67 | 158,181,468 | Yes
SAkbari2 | 74.398 ms | 72.187 ms | 1.41 | 253,311,101 | Yes
Heinz | 259.090 ms | 254.766 ms | 2.62 | 881,738,225 | Yes
正则表达糟透了!
答案 3 :(得分:3)
一些建议:
StringBuilder
。StringBuilder
内调整大小,请使用获取初始容量的构造函数,并将原始长度减去1。不要调用ToCharArray()
,因为它会分配一个新数组并将字符串复制到其中。
public static string RemoveRepeatedChars(string s)
{
if ((s == null) || (s.Length < 2))
return s;
// Return original string if no repeated char
int i = 1;
while ((i < s.Length) && (s[i] != s[i - 1]))
i++;
if (i == s.Length)
return s;
// i is index of first repeat
var sb = new StringBuilder(s.Length - 1);
sb.Append(s, 0, i); // add everything before the first repeat
char prevChar = s[i];
i++; // skip the first repeat
for (; i < s.Length; i++)
{
if (s[i] != prevChar)
{
sb.Append(s[i]);
prevChar = s[i];
}
}
return sb.ToString();
}
答案 4 :(得分:2)
这是一个LINQ解决方案:
string s = "reeeturrrnneeddryyf";
var result = string.Join("", s.Where((x, index) => index == s.Length - 1
|| x != s[index + 1]).ToArray());
或另一种方式:
var result = string.Join("", s.Zip(s.Skip(1), (first, second) => new[] { first, second })
.Where(z => z[0] != z[1]).Select(c => c[0])
.Concat(new[] { s[s.Length - 1] }));
或另一种方式:(使用扩展方法)
public static class Extensions
{
public static IEnumerable<T> TrimmingDuplicateCharacters<T>(this IEnumerable<T> source)
{
using (var iterator = source.GetEnumerator())
{
var comparer = EqualityComparer<T>.Default;
if (!iterator.MoveNext())
yield break;
var current = iterator.Current;
yield return current;
while (iterator.MoveNext())
{
if (comparer.Equals(iterator.Current, current))
continue;
current = iterator.Current;
yield return current;
}
}
}
}
然后:
var result = string.Join("", s.TrimmingDuplicateCharacters());
答案 5 :(得分:0)
//Program using C Language
#include <stdio.h>
int main()
{
char a[] = "rrrrreetttuurrneed";
int i = 0;
while(a[i])
{
if(a[i] != a[i+1])
printf("%c", a[i]);
i++;
}
printf("\n");
return 0;
}