检查回文中是否包含字符串:C#代码效率

时间:2019-06-01 19:03:54

标签: c# palindrome

我来自C的背景,最近开始用C#编写,所以请不要介意我的问题似乎有些基本。基本上,我想编写一个函数,如果字符串是回文,则返回true,否则返回false。

该字符串可能包含我必须忽略的字符,例如空格,“,”,“:”。我写了下面的代码

    static bool IsPalindrome(string s)
    {
        s = s.Replace(" ", "");
        s = s.Replace(",", "");
        s = s.Replace(":", "");

        int j = s.Length - 1;

        for(int i = 0; i < s.Length/2; i++)
        {
            if(s[i].ToString().Equals(s[j].ToString(),StringComparison.InvariantCultureIgnoreCase))
            {
                j--;
            }
            else
            {
                return false;
            }
        }
        return true;

    }

将使用以下字符串

调用函数
string s = "A man, a plan, a canal: Panama";

我在文档中读到,在C#中,字符串是不可变的,因此每次我执行诸如replace或ToString之类的操作时,都会创建一个新副本。

所以我想检查一下 一世)。此代码有效吗? ii)。如果没有,如何提高效率。

4 个答案:

答案 0 :(得分:2)

您无需使用.Replace或创建新字符串,只需在比较时跳过不需要的字符即可。

static bool IsPalindrome(string s)
{
    var i = 0;
    var j = s.Length - 1;
    while (j > i)
    {
        if (s[i] == ':' || s[i] == ',' || s[i] == ' ')
        {
            i++;
            continue;
        }
        if (s[j] == ':' || s[j] == ',' || s[j] == ' ')
        {
            j--;
            continue;
        }

        if (char.ToUpperInvariant(s[i++]) != char.ToUpperInvariant(s[j--])) return false;
    }

    return true;
}

答案 1 :(得分:1)

与您编写的for loop相比,这是一种更易于阅读的原告检测方法:

一种简短的方法,但由于Array.Reverse会颠倒元素的顺序,因此不一定有效:

static bool IsPalindrome(string s)
{
    s = s.Replace(" ", "");
    s = s.Replace(",", "");
    s = s.Replace(":", "");

    char[] array = s.ToCharArray();
    Array.Reverse(array);
    string backwards = new string(array);

    return s == backwards;
}

需要更多代码行的更有效方法是:

    static bool IsPalindrome(string s)
    {
        s = s.Replace(" ", "");
        s = s.Replace(",", "");
        s = s.Replace(":", "");

        int i = 0;
        int j = s.Length - 1;

        while (i < j)
        {
            if (s[i].ToString().ToLower() != s[j].ToString().ToLower())
                return false;

            i++;
            j--;
        }
        return true;
    }

另一种类似于第二种方法,但不需要将char转换为String进行比较:

    static bool IsPalindrome(string s)
    {
        s = s.Replace(" ", "");
        s = s.Replace(",", "");
        s = s.Replace(":", "");

        int i = 0;
        int j = s.Length - 1;

        while (i < j)
        {

            if (!char.ToLower(s[i]).Equals(char.ToLower(s[j])))
                return false;

            i++;
            j--;
        }
        return true;
    }

答案 2 :(得分:0)

如果您来自C背景,则应该熟悉此解决方案。无需分配一堆新字符串。只需忽略非字母字符即可。

.NET中似乎没有char值的大小写不敏感的比较,因此此代码假定ToLower(...)与当前区域性是足够的。

public static bool EqualsIgnoreCase(char c1, char c2)
{
    var culture = System.Globalization.CultureInfo.CurrentCulture;
    return Char.ToLower(c1, culture) == Char.ToLower(c2, culture);
}

public static bool IsPalindrome(string s)
{   
    switch (s?.Length ?? 0)
    {
        case 0:
            return false;
        case 1:
            return true;
        case 2:
            return EqualsIgnoreCase(s[0], s[1]);
        case 3:
            return EqualsIgnoreCase(s[0], s[2]);
    }

    var firstIndex = 0;
    var lastIndex = s.Length - 1;

    do
    {
        while (!Char.IsLetter(s[firstIndex]))
            ++firstIndex;
        while (!Char.IsLetter(s[lastIndex]))
            --lastIndex;
        if (!EqualsIgnoreCase(s[firstIndex++], s[lastIndex--]))
            return false;

    } while (firstIndex < lastIndex);

    return true;
}

答案 3 :(得分:0)

强制性的但效率低的LINQ解决方案:

static bool IsPalindrome(string s)
{
    return s.Where(Char.IsLetterOrDigit).Take(s.Length / 2)
        .SequenceEqual(s.Reverse().Where(Char.IsLetterOrDigit).Take(s.Length / 2));
}