I've written a recursion that checks if a string is a palindrome :
public static bool IsPalindrome(string value)
{
if ( value == null )
return false;
if ( value.Length == 0 )
return true;
return isPalindrome(value, 0, value.Length - 1);
}
private static bool isPalindrome(string value, int startChar, int endChar)
{
if ( value[startChar] != value[endChar] )
return false;
if ( startChar >= endChar )
return true;
return isPalindrome(value, startChar + 1, endChar - 1);
}
However I tried to find a way to do the same algorithm without using an auxiliary method that does the recursion (isPalindrome(.. , .. , ..)) however I still need the call of isPalindrome(...) .
How can I combine the two functions into one , where the recursion algorithm wouldn't make a call to any additional functions ?
Would replacing the separate method with an anonymous one be acceptable:
public static bool IsPalindrome(string value)
{
if (value == null)
return false;
if (value.Length == 0)
return true;
Func<string, int, int, bool> ip = null;
ip = (v, sc, ec) =>
{
if (v[sc] != v[ec])
return false;
if (sc >= ec)
return true;
return ip(v, sc + 1, ec - 1);
};
return ip(value, 0, value.Length - 1);
}
Here:
public static bool IsPalindrome(string value)
{
if ( value == null )
return false;
if ( value.Length <= 1 )
return true;
if ( value[0] != value[value.Length - 1] )
return false;
return IsPalindrome(value.Substring(1,value.Length - 2));
}
Performance would suck though... because this allocates n/2 strings...
You could do something a little smarter with an array window wrapper... But i don't recall .Net having those built in...
Option 2 :
public static bool IsPalindrome(IEnumerable<char> value)
{
if (value == null)
return false;
if (value.Count() <= 1)
return true;
if (value.First() != value.Last())
return false;
return IsPalindrome(value.Skip(1).Take(value.Count() - 1));
}
This has some hope of better performance... depending on how LINQ does specializations...
Tested the second one, and its dreadfully slow....
How about using a while-loop:
using System;
public class Program
{
public static void Main()
{
Console.WriteLine(IsPalindrome("TEST"));
Console.WriteLine(IsPalindrome("TESTSET"));
}
public static bool IsPalindrome(string value)
{
if ( value == null )
return false;
if ( value.Length == 0 )
return true;
int startChar = 0;
int endChar = value.Length - 1;
while(value[startChar] == value[endChar] && startChar < endChar)
{
startChar++;
endChar--;
if(startChar >= endChar) return true;
}
return false;
}
}
Output:
False
True
I like your recursive solution much more though.
EDIT
Or... you could do it with one statement:
public static bool IsPalindrome(string value)
{
if ( value == null )
return false;
return value == new String(value.ToCharArray().Reverse().ToArray());
}
EDIT
And another solution using a for-loop. It is similar to doing a reverse and then compare.
public static bool IsPalindrome(string value)
{
if ( value == null )
return false;
for(int i = 0, j = value.Length - 1; i < j; i++, j--) {
if(value[i] != value[j]) return false;
}
return true;
}
I would suggest something like this:
public static bool IsPalindrome(string value)
{
if ( value == null )
return false;
if ( value.Length == 0 )
return true;
int i=0;
bool _cont = true;
while(_cont){
if ( value[startChar+i] != value[endChar-i] ){
_cont = false;
return false;
if ( (startChar+i) >= (endChar-i) ){
i++;
}
else{
_cont = false;
return true;
}
}
}
Related
I'm very new to c# so please excuse my lack of knowledge. I'm just trying to check the following:
"CardNumberLength" = 16
"CardPINLength" = 3
"CardNameHasSpace" 0
I don't want to use an if else statement, is there another way?
The code:
public bool Validate()
{
CardNumberLength = Convert.ToString(GetCardNumber()).Length;
CardPINLength = Convert.ToString(GetCardPIN()).Length;
CardNameHasSpace = GetCardName().IndexOf(" ");
}
You could just return the boolean result:
return CardNumberLength == 16 && CardPINLength == 3 && CardNameHasSpace >= 0;
If you absolutely had to do this without if tests, you could mash them together in a return statement. It's just a different syntax to express the same logic. I probably wouldn't suggest doing this without if tests though.
public bool Validate()
{
return Convert.ToString(GetCardNumber()).Length == 16 //replaces CardNumberLength
&& Convert.ToString(GetCardPin()).Length == 3 // replaces CardPINLength
&& GetCardName().IndexOf(" ") < 1; // replaces CardNameHasSpace
}
public bool Validate()
{
int CardNumberLength = int.Parse(GetCardNumber().ToString().Length);
int CardPINLength = int.Parse(GetCardPIN().ToString().Length);
bool CardNameHasSpace = GetCardName().Contains(" ");
return CardNumberLength == 16 && CardPINLength == 3 && !CardNameHasSpace
}
using the .ToString() on an object is way better than Convert.ToString(), also you can check inside a string if it contains a certain string with the .Contains(string) function on a string.
public bool Validate()
{
CardNumberLength = Convert.ToString(GetCardNumber()).Length;
CardPINLength = Convert.ToString(GetCardPIN()).Length;
CardNameHasSpace = GetCardName().IndexOf(" ");
return CardNumberLength == 16 && CardPINLength == 3 && CardNameHasSpace > -1;
}
Or
public bool Validate()
{
CardNumberLength = Convert.ToString(GetCardNumber()).Length;
CardPINLength = Convert.ToString(GetCardPIN()).Length;
CardNameHasSpace = GetCardName().IndexOf(" ");
if (CardNumberLength != 16)
return false;
if (CardPINLength != 3)
return false;
if (CardNameHasSpace == -1)
return false;
return true;
}
Perhaps, this helps you :)
i'm trying to make a class that contains 4 functions: isLong, isDouble, stringToLong, and stringToDouble. I am trying to do this without using a TryParse function. Ideally this class would receive a string and return the appropriate type (bool, bool, long, and double) in respective order.
For instance if i enter the number 100000 it returns True (bool) for isLong.
Below is an example of how i did isLong but i am having difficulty trying to do the same for isDouble for receiving decimals and for both stringToLong/stringToDouble.
public static bool isLong(string s)
{
bool ret = true;
int i;
s = s.Trim();
if (s[0] == '-')
{
i = 1;
}
else
{
i = 0;
}
for (; (i < s.Length); i = i + 1)
{
ret = ret && ((s[i] >= '0') && (s[i] <= '9'));
}
return (ret);
}
You could use MinValue and MaxValue properties for check numeric types, for instance you could define a method like this:
public bool IsLong(decimal value)
{
return value >= long.MinValue && value <= long.MaxValue && value == (long)value;
}
I want to know how Microsoft write algorithm for string comparison.
string.equal and string.compare
Do they compare character by character like this:
int matched = 1;
for (int i = 0; i < str1.Length; i++)
{
if (str1[i] == str2[i])
{
matched++;
}
else
{
break;
}
}
if (matched == str1.Length) return true;
Or match all at once
if (str1[0] == str2[0] && str1[1] == str2[1] && str1[2] == str2[2]) return true;
I trying pressing F12 on the string.equal function but it got me to the function declaration not the actual code. Thanks
After Thilo mentioned to look at the source i was able to find this... this is how Microsoft wrote it.
public static bool Equals(String a, String b) {
if ((Object)a==(Object)b) {
return true;
}
if ((Object)a==null || (Object)b==null) {
return false;
}
if (a.Length != b.Length)
return false;
return EqualsHelper(a, b);
}
But this raise a question whether is faster by checking character by character or doing a complete match?
Looking at the source (copied below):
null check
reference identity
different length => not equal
go over the binary encoding of the characters in a bit of an unrolled loop
this raise a question whether is faster by checking character by character or doing a complete match
I don't understand the question. You cannot do a "complete match" without checking each of the characters. What you can do is bail out as soon as you find a mismatch. That reduces runtime a bit, but does not change the fact that it is O(n).
// Determines whether two strings match.
[Pure]
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
public bool Equals(String value) {
if (this == null) //this is necessary to guard against reverse-pinvokes and
throw new NullReferenceException(); //other callers who do not use the callvirt instruction
if (value == null)
return false;
if (Object.ReferenceEquals(this, value))
return true;
if (this.Length != value.Length)
return false;
return EqualsHelper(this, value);
}
[System.Security.SecuritySafeCritical] // auto-generated
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
private unsafe static bool EqualsHelper(String strA, String strB)
{
Contract.Requires(strA != null);
Contract.Requires(strB != null);
Contract.Requires(strA.Length == strB.Length);
int length = strA.Length;
fixed (char* ap = &strA.m_firstChar) fixed (char* bp = &strB.m_firstChar)
{
char* a = ap;
char* b = bp;
// unroll the loop
#if AMD64
// for AMD64 bit platform we unroll by 12 and
// check 3 qword at a time. This is less code
// than the 32 bit case and is shorter
// pathlength
while (length >= 12)
{
if (*(long*)a != *(long*)b) return false;
if (*(long*)(a+4) != *(long*)(b+4)) return false;
if (*(long*)(a+8) != *(long*)(b+8)) return false;
a += 12; b += 12; length -= 12;
}
#else
while (length >= 10)
{
if (*(int*)a != *(int*)b) return false;
if (*(int*)(a+2) != *(int*)(b+2)) return false;
if (*(int*)(a+4) != *(int*)(b+4)) return false;
if (*(int*)(a+6) != *(int*)(b+6)) return false;
if (*(int*)(a+8) != *(int*)(b+8)) return false;
a += 10; b += 10; length -= 10;
}
#endif
// This depends on the fact that the String objects are
// always zero terminated and that the terminating zero is not included
// in the length. For odd string sizes, the last compare will include
// the zero terminator.
while (length > 0)
{
if (*(int*)a != *(int*)b) break;
a += 2; b += 2; length -= 2;
}
return (length <= 0);
}
}
public static int isPalindrome(char[] String)
{
if (String.Length == 0 || String.Length == 1)
return 1;
if (String[0] != String[String.Length - 1])
return 0;
return Convert.ToUInt32(isPalindrome(String);
}
I am not able to make it as instance method i am getting problems so please help me how to make it as dynamic
This should work:
public static int isPalindrome(char[] String)
{
string smallerString = String.ToString().Substring(1, String.Length - 1);
if (String.Length == 0 || String.Length == 1)
return 1;
if (String[0] != String[String.Length - 1])
return 0;
return Convert.ToInt32(isPalindrome(smallerString.ToCharArray()));
}
Without changing your types and return values
public static int isPalindrome(char[] str)
{
if (str.Length == 0 || str.Length == 1)
return 1;
if (str[0] != str[str.Length - 1])
return 0;
return isPalindrome(str.Skip(1).Take(str.Length-2).ToArray());
}
You are passing the same value to isPalindrome again and again. You can try something like the following (note I've used string in the example below):
private static bool isPalindrome(string s)
{
if(s.Length == 1 || s.Length == 0)
return true;
if(s[0] != s[s.Length -1])
return false;
return isPalindrome(s.SubsString(1, s.Length -2));
}
I think it could be very easy implemented.
public static bool IsPalindrome(String text)
{
if(string.IsNullOrWhiteSpace(text))
return false;
char[] arr = text.ToCharArray();
Array.Reverse(arr);
var reversedText = new string(arr);
return string.Equals(text, reversedText, StringComparison.OrdinalIgnoreCase);
}
I am trying to write a function to control if the parenthesis included in a stringare balanced or not.
I have written the following function:
public bool IsBalanced(string input)
{
//last condition, gets out
if (string.IsNullOrEmpty(input)) return true;
int numOpen = 0;
bool opened = false;
foreach (char c in input)
{
if (char.ToUpperInvariant(c) =='(')
{
opened = true;
numOpen+=1;
}
if (char.ToUpperInvariant(c) == ')')
{
if (opened)
{
numOpen-=1;
opened = numOpen > 0;
}
else
return false; //incorrect position parentheses, closes but not opened
}
}
return numOpen == 0;
}
I wanted to change it to a recursive function, but have not been able to do so. Could anyone give a hint how to do it?
Well, your algorithm is not pretty. Here is a better one
int check = 0;
foreach (var c in input)
{
if (c == '(') {
check++;
} else if (c == ')') {
check--;
}
if (check < 0) {
return false; // error, closing bracket without opening brackets first
}
}
return check == 0; // > 0 error, missing some closing brackets
To make it (algorithm of checking for balanced brackets) recursive you can go with following
bool IsBalanced(string input)
{
var first = input.IndexOf('('); // first opening bracket position
var last = input.LastIndexOf(')'); // last closing bracket position
if (first == -1 && last == -1)
return true; // no more brackets - balanced
if (first == -1 && last != -1 || first != -1 && last == -1)
return false; // error - one of brackets is missing
if (first > last)
return false; // error - closing bracket is BEFORE opening
return IsBalanced(input.Substring(first, last - first)); // not sure, might need to tweak it, parameter should be without first and last bracket (what is inside)
}
This simply remove first opening brackets and last closing bracket and pass what is left as parameter (recursively) until one of the end conditions is met.
The basic idea is to take a variant (numOpen in this case) as an argument.
Here is my code:
public bool IsBalancedRec(string input, int numOpen = 0)
{
if (numOpen < 0)
return false;
if (string.IsNullOrEmpty(input))
return numOpen == 0;
char c = input[0];
string rest = input.Substring(1);
if (c == '(')
return IsBalancedRec(rest, numOpen + 1);
else if (c == ')')
return IsBalancedRec(rest, numOpen - 1);
else
return IsBalancedRec(rest, numOpen);
}
And call this like IsBalancedRec("so(m(eth)ing)").
Implement with stack:
Stack myStak = new Stack();
public bool IsBalanced(string input)
{
if (input.ToArray().Count() != 0)
{
if(input.ToArray()[0] == '(')
{
myStak.Push('(');
}
else if(input.ToArray()[0] == ')')
{
if (myStak.Count != 0)
myStak.Pop();
else
{
//not balanced
return false;
}
}
return IsBalanced(input.Substring(1));
}
else
{
if (myStak.Count == 0)
{
//balanced
return true;
}
else
{
//not balanced
return false;
}
}
}
public static bool IsBalanced(string input)
{
int numOpen = 0;
while(input != "")
{
char c = input[0];
input = input.Substring(1);
numOpen = c == '(' ? (numOpen + 1) : (c == ')' ? (numOpen - 1) : numOpen);
}
return numOpen == 0;
}
// count no of left and right bracket or parenthesis and check counts
var InputStr= str.ToCharArray();
int left = 0;
int right = 0;
foreach (char item in InputStr)
{
if(item == '(')
{
left ++;
} else if(item == ')')
{
right ++;
}
}
if(right == l)
{
return "1";
}
return "0";
}