我编写了两个代码段来检查给定的字符串是否是回文式:

public static bool FirstMethod(string str)
{
    int i = 0;
    int j = str.Length - 1;

    while (i<j)
    {
        if (str[i] != str[j])
            return false;

        i++;
        j--;
    }

    return true;
}




public static bool SecondMethod(string myString)
{
    string first = myString.Substring(0, myString.Length / 2);
    char[] arr = myString.ToCharArray();
    Array.Reverse(arr);
    string temp = new string(arr);
    string second = temp.Substring(0, temp.Length / 2);
    return first.Equals(second);
}


请告诉我哪个更好。

还有比这更好的方法吗?

评论

我不确定提出的任何一种方法是否是实际有效的响应。维基百科将回文词定义为:回文词是单词,词组,数字或其他符号或元素的序列,其读入相同的正向或反向,并且通常允许对标点和单词分隔符进行调整。著名的例子包括“阿莫尔,罗马”,“一个人,一个计划,一条运河:巴拿马”和“尼克松”中没有“ x”。这两种方法都无法消除标点符号或空格。

正则表达式怎么样?

现在编写一个考虑UTF-16代理对和Unicode组合字符的版本:-)

绩效对您来说有多重要?为了提高可读性,我希望使用简单的解决方案:myString == new String(myString.Reverse()。ToArray());

@Voo我曾经实现过,仅使用char类型的方法,确实很烦人。但是后来我了解了StringInfo类,该类可以将字符串拆分为文本元素。使用它,具有unicode意识的解决方案仅比天真的方法复杂。

#1 楼

由于某些原因,我希望选择第一个。


我认为它更具可读性和易懂性。
只有一个字符串,因此开销较小。 (除非被大量调用,否则可以忽略不计。)
只有一个数组。反向创建第二个数组。


话虽如此,所以需要进行实际审查。


返回布尔值的方法的名称应采用IsSomethingHasSomething的形式。一个很好的名字是IsPalindrome
两个方法都不能接受字符串。数字也可以是回文的。如果我们也可以将一个整数也传递给它,那不是一个很好的补充吗? (不必在传递它之前显式调用.ToString()。)
我喜欢您只检查i < j而不是i <= j。当字符数为奇数时,它将节省无用的迭代。
我也喜欢while循环。它比另一个答案建议的for循环干净得多。
我不会在第二种方法上讲太多,因为我认为@elios提供了很好的实现。


评论


\ $ \ begingroup \ $
在我的实际代码中,FirstMethod的名称是“ IsPalindrome”,我以这种方式命名的目的只是为了提问:)...第二点,是的,我没有检查回文数。点最初我添加了i <= j,然后我意识到对于奇数个字符,中间值将是相同的..感谢指出
\ $ \ endgroup \ $
–罗希特
2014年7月29日在17:46



\ $ \ begingroup \ $
我实际上认为不检查回文数是一件好事。首先,这意味着您必须编写更少的代码。第二,我拒绝数字本身可以回文的假设。例如,22将是所谓的回文数。但是,二进制数22是10110,不是回文。要检查数字是否为回文,您需要知道数字系统(以10为底,以2为底,以16为底)。
\ $ \ endgroup \ $
– Sjoerd Job Postmus
2014年7月29日在19:52



\ $ \ begingroup \ $
我同意,这将是一个很好的扩展。但是,我担心它是人们必须做的事情,而不是可以添加的功能,如果是的话,它只会在发现需求之后才出现。但是,对于接受数字,我确实认为应该提供一个基数,如果语言支持,则可以选择默认为10。 (顺便说一句,我赞成。我完全同意所有其他言论。)
\ $ \ endgroup \ $
– Sjoerd Job Postmus
2014年7月29日在20:11

\ $ \ begingroup \ $
@ ckuhn203:关于“赛车”和“路线”,我认为这不等于需要了解基础。数字本身并不是由单独的实体组成的,只有选择表示形式(二进制,十进制,十六进制),我们才能得到由实体的有序列表组成的东西。一百二十一成为实体1、2、1(正好按该顺序)。我想补充一下,不仅字符串可以是回文的,而且可以是任何项目列表(支持相等性)。选择的算法仍然是我的选择。
\ $ \ endgroup \ $
– Sjoerd Job Postmus
2014年7月29日在20:17



\ $ \ begingroup \ $
@WernerCD,法语中的racecar与英语中的racecar不同。 0xF和15是相同的数字,表示相同的事物。 equal(15,0xF)是true,但是equal(“ racecar”,“ voiture de course”)是false。
\ $ \ endgroup \ $
–乔纳森。
14年7月30日在18:38

#2 楼

以下是此问题的最常见解决方案:

public static bool IsPalindrome(string s)
{
    char[] array = s.ToCharArray();
    Array.Reverse(array);
    string backwards = new string(array);

    return s == backwards;
}


,如果您使用的是Linq:

public static bool IsPalindrome(string s)
{
    return s == new string(s.Reverse().ToArray());
}


但是如果您打算执行此代码数千次(我对此表示怀疑),则您的第一种方法将是最快的。

#3 楼

我同意@ ckuhn203的观点,因为第一个看起来更干净。

我不太了解C#及其样式,但是在CI中,绝对希望使用for循环:

public static bool FirstMethod(string str)
{
    for (int i = 0, j = str.Length - 1; i < j; i++, j--) {
        if (str[i] != str[j]) {
            return false;
        }
    }
    return true;
}


#4 楼

考虑使用LINQ:

static bool IsPalindrome(string s)
{
    var characterPairs = s.Zip(s.Reverse(), (l, r) => l == r);
    return characterPairs.Take(s.Length / 2).All(isMatch => isMatch);
}


评论


\ $ \ begingroup \ $
System.String中没有Reverse方法
\ $ \ endgroup \ $
– elios264
14年7月29日在16:57

\ $ \ begingroup \ $
@ elios264使用System.Linq;
\ $ \ endgroup \ $
–dss539
2014年7月29日在16:59



\ $ \ begingroup \ $
如果要成为身份,您不需要将lambda传递给All
\ $ \ endgroup \ $
– jk。
14年7月29日在21:04

\ $ \ begingroup \ $
@jk。我希望那是真的。看起来会更干净。但是...错误1方法'All'的重载没有接受0个参数
\ $ \ endgroup \ $
–dss539
2014年7月30日15:36

\ $ \ begingroup \ $
@ dss539你说得对! Any具有超载但All没有的奇特之处
\ $ \ endgroup \ $
– jk。
2014年7月30日在16:46

#5 楼

第一个可能要快一些,第二个可以清理一点,但更易于阅读。除非您知道遇到性能问题,否则请选择第二个。

对于第二个选项,您应该从原始输入字符串中提取两个子字符串,分别称为“ firstHalf”和“ secondHalf”,分别对应于输入字符串的前一半和后一半。然后反转“ secondHalf”并进行比较。

#6 楼

使用LINQ编写此内容的另一种方法,尽管我不确定它是否更清晰:

Enumerable.Range(0, str.Length / 2).All(i => str[i] == str[str.Length - i - 1])


评论


\ $ \ begingroup \ $
最后一个答案!
\ $ \ endgroup \ $
– elios264
14年7月29日在18:49

\ $ \ begingroup \ $
@ elios264我的回答也可以是一行,但是为了便于阅读,我将其分开。返回s.Zip(s.Reverse(),(l,r)=> l == r).Take(s.Length / 2).All(b => b)
\ $ \ endgroup \ $
–dss539
14年7月29日在19:15

#7 楼

如果至少一个人不以递归为例,我的计算机科学老师将上交。我本人不是C#家伙,但是如果您想呆呆,我认为这样做会有点像这样:

public static bool IsPalindrome(string str)
{
    int len = str.length - 1;

    return str[0] == str[len] && (
           len <= 1 || IsPalindrome( str.Substring(1,len) )
           );
}


新的字符串,您可能会编写此字符串,以便长字符串可以分布在多个内核中。那是1 / number_of_cores的改善!

#8 楼

我要补充一点,您可以使您的方法成为字符串的扩展方法。它只是强调说,作为回文集是某种形式的字符串表示的属性。

为了易于理解,第二种方法非常突出。基于索引的版本可以工作,但是如果大多数人不加提示地看到它,就会br之以鼻。

将字符串切成两半也是一种过早的优化,即使这当然是合乎逻辑的。更清楚地扭转和比较。如果某种程度上确实是瓶颈,则将其切成两半。

评论


\ $ \ begingroup \ $
我立即知道该代码在做什么,为什么人们会挠头?
\ $ \ endgroup \ $
–马拉奇♦
14年7月29日在16:50

\ $ \ begingroup \ $
我同意@Malachi。实际上,第一个版本更容易阅读。但是,我最初的背景是C / C ++,所以也许就是这个原因。信息密度较高。 #2看起来像某些Java Enterprise Architect编写的。 (不一定是坏事)
\ $ \ endgroup \ $
–dss539
14年7月29日在16:58

\ $ \ begingroup \ $
索引操纵版本一点都不明显。我假设有人会在浏览代码,而不是解析每一点。您必须了解一个事实,即i和j彼此相对移动,并想一想为什么它们交叉时会停止。第二种方法实际上在代码中说“反向”并进行比较。
\ $ \ endgroup \ $
–卡洛斯
2014年7月29日在18:42



\ $ \ begingroup \ $
这是一个非常基本的算法。如果与我一起工作的人看到它并且不理解它,我会担心他们的能力水平。循环和数组应该是您作为程序员学习的第一件事。
\ $ \ endgroup \ $
–RubberDuck
14年7月29日在19:02

\ $ \ begingroup \ $
@ ckuhn203我认为Carlos的意思不是说他不理解它,而是花了比第二版更长的时间来理解。如果我没有C / C ++的背景知识,那么我很容易看出这一点。
\ $ \ endgroup \ $
–dss539
14年7月29日在19:13

#9 楼

另一个无耻的linq答案,不需要反转或创建新的枚举,只需要达到以下要求即可:

public static bool IsPalindrome(this string str)
{
    int len = str.Length;
    return str.Take(len / 2).All(o => o == str[--len]);
}