Determine if a string is a palindrome with C# .NET
October 14, 2020 Leave a comment
Here comes another classic coding question that you might come across during an interview. Write a function that accepts a string and returns a boolean. The function must determine if the string is a palindrome. A string is a palindrome if it has the same value in both directions: forward and backward. Examples:
- abba
- qwertrewq
- 1234321
In this post we’ll look at two different solutions, but there are certainly others. Also, we’ll implement case-sensitive solutions, i.e. the following will return false:
- aBba
- qWertrewq
The first solution is based on looping through the characters of the string. In each iteration we compare the characters on two extremes from the midpoint. The midpoint is simply the string length divided by 2. Say we have the following string of length 8 chars:
q | w | e | r | r | e | w | q |
The midpoint of this string is 4. We start by comparing the char at position 0 with the char at position length - 1
, i.e. ‘q’ with ‘q’. Then we continue with position 1 and position length - 2
, that is ‘w’ and ‘w’. We continue until we reach the midpoint, i.e. position 4 and compare ‘r’ with ‘r’. This is the end of the loop and the function returns true.
What if we have an odd number of characters in the string? The same algorithm will still work, here’s an example:
q | w | e | r | e | w | q |
The midpoint is 3 in this case: 7 / 2 = 3.5 and .NET will turn it into 3 when boxing it into an integer. So we compare ‘q’ with ‘q’, then ‘w’ with ‘w’ and finally ‘e’ with ‘e’. We don’t need to worry about ‘r’, the char in the very middle is always symmetrical with itself.
Here’s all of that in code form:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Algorithms
{
public class Palindrome
{
public bool IsPalindrome(string str)
{
return IsPalindromeWithLoop(str);
}
private bool IsPalindromeWithLoop(string str)
{
for (int i = 0; i < str.Length / 2; i++)
{
if (str[i] != str[str.Length - i - 1])
{
return false;
}
}
return true;
}
}
}
…and here come a couple of unit tests:
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace Algorithms.Tests
{
[TestClass]
public class PalindromeTests
{
[TestMethod]
public void IsPalindromeTest()
{
Palindrome palindrome = new Palindrome();
Assert.IsTrue(palindrome.IsPalindrome("abba"));
Assert.IsTrue(palindrome.IsPalindrome("qwewq"));
Assert.IsTrue(palindrome.IsPalindrome("12344321"));
Assert.IsFalse(palindrome.IsPalindrome(" hehe "));
Assert.IsFalse(palindrome.IsPalindrome("Hello olleh")); //case sensitive!!
Assert.IsTrue(palindrome.IsPalindrome(" abba "));
}
}
}
The second solution is based on a simple string comparison. We take the incoming string, reverse it and compare the original with the reversed string:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Algorithms
{
public class Palindrome
{
public bool IsPalindrome(string str)
{
return IsPalindromeWithReverse(str);
//return IsPalindromeWithLoop(str);
}
private bool IsPalindromeWithReverse(string str)
{
if (str == null) return false;
var reverse = string.Join("", str.Reverse());
return str == reverse;
}
}
}
The Reverse()
extension method creates an IEnumerable
of chars, i.e. not a string. We take that char collection and join its elements into a string. The empty string in the string.Join
function is the delimiter, meaning that we don’t want to put anything in between the chars when joining them. Finally we compare the two strings as the return value of the function.
Run the unit tests, they will pass as expected.