Find out how long the longest sequence is in a string
I recently had this question in an interview and this is what I came up with. Any feedback?
Find out how long the longest sequence is in a string. For example, in the string "abccdeeeeef" the answer would be 5.
static int LongestSeq(string strPass)
{
int longestSeq 开发者_高级运维= 0;
char[] strChars = strPass.ToCharArray();
int numCurrSeq = 1;
for (int i = 0; i < strChars.Length - 1; i++)
{
if (strChars[i] == strChars[i + 1])
{
numCurrSeq++;
}
else
{
numCurrSeq = 1;
}
if (longestSeq < numCurrSeq)
{
longestSeq = numCurrSeq;
}
}
return longestSeq;
}
This will return 0 for strings of length 1 (when it should return 1).
First comment: you don't need to convert it to a char array. You can index straight into the string.
Second comment: you could easily generalize this to IEnumerable<T>
if you wanted to, using foreach
and remembering the "current" item.
Third comment: I think the comparison between longestSeq
and numCurrSeq
would be clearer as:
if (numCurrSeq > longestSeq)
To me that's more natural as I usually have the varying part of the expression first.
Just to add my 2 pence in, here's an alternative using Regex:
string source = "eeabccdeeeeef";
Regex reg = new Regex(@"(\w)\1+");
MatchCollection matches = reg.Matches(source);
int longest = 0;
foreach (System.Text.RegularExpressions.Match match in matches)
{
if (longest < match.Length) longest = match.Length;
}
Due to not reading the question properly in the first place when posting my previous answer, I should probably add in some actual feedback considering that's the question posted by the OP. However, every point I've come up with has been mentioned by Henrik or Job Skeet, so I'll just stress the point Jon Skeet made; you do not have to convert a string to a char array, you can just index a particular point in the string as follows:
char letter = someString[4];
So it should all still work if you replace strChars
with strPass
.
You can always rember the last character, so you don't need to access the array twice in an iteration.
Inside your loop you can use another loop which iterates as long as the current character is the same as the last character. After this subloop you can place the check if the current numCurrSeq > longestSeq you you don't need this check every iteration but for every subsequence.
I don't really know whatever langauge this is (C#?) so excuse any minor syntactic glitches (I don't know if it's "else if" or "elseif" or "elif" or something else)
static int LongestSeq(string strPass)
{
int longestSeq = 1;
int curSeqStart = 0;
for (int i = 1; i < strPass.Length; i++)
{
if (strPass[i] != strPass[curSeq])
{
curSeqStart = i;
}
else if (i - curSeqStart + 1 > longestSeq)
{
longestSeq = i - curSeqStart + 1;
}
}
return longestSeq;
}
It might be more efficient to do
...
else
{
len = i - curSeqStart + 1
if ( len > longestSeq )
{
longestSeq = len;
}
}
or even just
...
else
{
longestSeq = max(longestSeq, i - curSeqStart + 1)
}
depending on how good your 'max' implementation and compiler are.
I think this works? I don't ussually write recursive methods, I would have totally come up with the posters answer..
public static int recurse(Char last, int seqLength, int currentIndex, int largestSeqLength, string source)
{
if (currentIndex > source.Length)
{
return largestSeqLength;
}
if (source[currentIndex] == last)
{
seqLength++;
if (seqLength > largestSeqLength)
{
largestSeqLength = seqLength;
}
}
else
{
seqLength = 1;
}
return recurse(source[currentIndex], seqLength, currentIndex++, largestSeqLength, source);
}
And another implementation
public static int LongestSeq<T>(this IEnumerable<T> source)
{
if (source == null)
throw new ArgumentNullException("source");
int result = 0;
int currentCount = 0;
using (var e = source.GetEnumerator())
{
var lhs = default(T);
if (e.MoveNext())
{
lhs = e.Current;
currentCount = 1;
result = currentCount;
}
while (e.MoveNext())
{
if (lhs.Equals(e.Current))
{
currentCount++;
}
else
{
currentCount = 1;
}
result = Math.Max(currentCount, result);
lhs = e.Current;
}
}
return result;
}
A simple (untested) solution would be:
int GetLongestSequence(string input)
{
char c = 0;
int maxSequenceLength = 0;
int maxSequenceStart = 0;
int curSequenceLength = 0;
int length = input.Length;
for (int i = 0; i < length; ++i)
{
if (input[i] == c)
{
++curSequenceLength;
if (curSequenceLength > maxSequenceLength)
{
maxSequenceLength = curSequenceLength;
maxSequenceStart = i - (curSequenceLength - 1);
}
}
else
{
curSequenceLength = 1;
c = input[i];
}
}
return maxSequenceStart;
}
Or a better structured code (also untested):
private int GetSequenceLength(string input, int start)
{
int i = start;
char c = input[i];
while (input[i] == c) ++i; // Could be written as `while (input[i++] == c);` but i don't recommend that
return (i - start);
}
public int GetLongestSequence(string input)
{
int length = input.Length;
int maxSequenceLength = 0;
int maxSequenceStart = 0;
for (int i = 0; i < length; /* no ++i */)
{
int curSequenceLength = this.GetSequenceLength(input, i);
if (curSequenceLength > maxSequenceLength)
{
maxSequenceLength = curSequenceLength;
maxSequenceStart = i;
}
i += curSequenceLength;
}
return maxSequenceStart;
}
This extension method find the longest sequence of same characters in a string.
public static int GetLongestSequenceOfSameCharacters(this string sequence)
{
var data = new List<char>();
for (int i = 0; i < sequence.Length; i++)
{
if (i > 0 && (sequence[i] == sequence[i - 1]))
{
data.Add(sequence[i]);
}
}
return data.GroupBy(x => x).Max(x => x.Count()) + 1;
}
[TestMethod]
public void TestMethod1()
{
// Arrange
string sequence = "aabbbbccccce";
// Act
int containsSameNumbers = sequence.GetLongestSequenceOfSameCharacters();
// Assert
Assert.IsTrue(containsSameNumbers == 5);
}
精彩评论