不使用乘法C#将字符串转换为整数


9

有没有一种方法可以将字符串转换为整数而不使用乘法。int.Parse()的实现也使用乘法。我还有其他类似的问题,您可以在其中手动将字符串转换为int,但这还需要将数字乘以10为底。这是我在一次采访中遇到的一个采访问题,我似乎找不到任何答案。


3
有(文字)还是没有(标题)?
d4zed

2
你能澄清一下吗?您的标题说“不”使用,而您的文字说“不”使用...
vonludi

1
考虑到问题的其余内容(例如“但还需要将数字乘以10为底”),标题是正确的。另外,如果允许乘法,那么这是微不足道的,所以问它没有道理。
约翰

7
本文建议用移位和加法(x<<1 + x<<3)将乘数替换为10 ,但这仍然是使用乘法的一种方式,因此很难说这是否是问题的
实质

3
是否for (int i = 0; i < 10; i++) result += number;算?
canton7

Answers:


12

如果您假设以10为底的数字系统并用位移代替了乘法(请参见此处),则这可能是正整数的解决方案。

public int StringToInteger(string value)
{
    int number = 0;
    foreach (var character in value)
        number = (number << 1) + (number << 3) + (character - '0');

    return number;
}

请参阅有关ideone的示例。

唯一的假设是,字符'0''9'位于字符集直接彼此相邻。使用将数字字符转换为整数值character - '0'

编辑:

对于负整数,此版本(请参见此处)适用。

public static int StringToInteger(string value)
{
    bool negative = false;
    int i = 0;

    if (value[0] == '-')
    {
        negative = true;
        ++i;
    }

    int number = 0;
    for (; i < value.Length; ++i)
    {
        var character = value[i];
        number = (number << 1) + (number << 3) + (character - '0');
    }

    if (negative)
        number = -number;
    return number;
}

通常,您应该考虑错误,例如空检查,其他非数字字符的问题等。


6

这取决于。我们是在谈论乘法的逻辑运算,还是在硬件中的实际运算方式?

例如,您可以将十六进制(或八进制,或任何其他基数为2的乘法器)字符串转换为整数“无乘法”。您可以逐个字符并保持或(|)和移位(<<)。这避免了使用*运算符。

对十进制字符串执行相同的操作比较棘手,但是我们仍然有简单的加法运算。您可以使用添加循环来完成相同的操作。做起来很简单。或者,您可以制作自己的“乘法表”-希望您在学校学习了如何对数字进行乘法;您可以使用计算机执行相同的操作。当然,如果您使用的是十进制计算机(而不是二进制计算机),则可以执行“ bitshift”操作,就像使用较早的十六进制字符串一样。即使使用二进制计算机,您也可以使用一系列移位- (a << 1) + (a << 3)与相同a * 2 + a * 8 == a * 10。小心负数。您可以找出很多使这个有趣的技巧。

当然,这两个都是变相的乘积。那是因为位置数字系统本质上是乘法的。这就是特定数字表示的工作方式。您可以使用隐藏此事实的简化方法(例如,仅需要0和的二进制数)1,因此您可以有一个简单的条件,而不是相乘-当然,您实际上所做的仍然是相乘,只有两个可能的输入和两个可能的输出),但它一直都在潜伏着。<<与相同* 2,即使执行该操作的硬件可以更简单和/或更快速。

要完全消除乘法,您需要避免使用位置系统。例如,罗马数字是累加的(请注意,实际的罗马数字没有用我们今天的紧凑化规则-四会IIII,不IV,这14可以在任何形式的像写XIIIIIIIIXIIXIIVVIIII等)。将这样的字符串转换为整数变得非常容易-逐个字符并继续添加。如果字符是X,则添加十。如果为V,则添加五个。如果I,添加一个。我希望您能理解为什么罗马数字在这么长的时间内仍然很流行。当您需要进行很多乘法和除法运算时,位置数值系统非常有用。如果您主要处理加法和减法,则罗马数字的效果很好,并且不需要太多的教育(并且算盘比位置计算器更容易制造和使用!)。

有了这样的作业,面试官的实际期望会受到很多折磨。也许他们只是想看看您的思维过程。您是否接受技术性(<<不是真正的乘法)?你知道数论和计算机科学吗?您只是沉迷于代码,还是要求澄清?您认为这是一个有趣的挑战,还是另一个荒谬而无聊的面试问题,与您的工作无关?我们不可能告诉您面试官正在寻找的答案。

但我希望至少能给您带来一些可能的答案:)


如果我们使用罗马数字系统,如果我们有不属于罗马数字系统的B,T,S,R,G,A等字符,您将如何添加。换句话说,如何获得一个int等效项?
Adheesh

@Adheesh我不知道您要问什么。您能举一个您认为有问题的例子吗?
a安

假设我们有一个字符串“ 12345”,我们想将其转换为一个int。如果我不想使用位置数字系统而是使用罗马数字系统怎么办。我们该怎么做?(我根本不想使用乘法)
Adheesh

@Adheesh在罗马数字系统中,字符串不是“ 12345”。这就是重点。位置数字系统本质上是乘法的。罗马数字系统是加法的。罗马字符串应类似于“ MMMMMMMMMMMMCCCCXXXXIIIII”。逐个字符,并不断增加数字。
a安

@Adheesh当然,在实际实践中,不会有那么长的笨拙烂摊子。而不是“ 12345米”,而是说“ XII公斤和CCCXXXXIIIII米”。旧的测量系统适用于计算能力不高的人-如果您只能计算十二个单位,只需将您可以用英制单位表示的值范围与现代单位进行比较:)
六安

5

考虑到这是一个面试问题,表现可能不是头等大事。为什么不只是:

private int StringToInt(string value)
{
    for (int i = int.MinValue; i <= int.MaxValue; i++)
        if (i.ToString() == value)
            return i;
    return 0; // All code paths must return a value.
}

如果传递的字符串不是整数,则该方法将引发溢出异常。


1
出色的:P只要确保没有面试官的即时反馈就不要使用它,尽管:DI想像甚至可以使用相同的基本方法,通过部分匹配来提高表现。至少,对负数进行简单检查可以节省一半的循环;检查奇数/偶数一半。
a安

@Luaan我想尽可能地减少行数:) ...public int StringToInt(string value, int search_from = int.MinValue) => value == search_from.ToString() ? search_from : StringToInt (value, ++search_from);
nl-x

可悲的是,这将爆炸:D但这是在纸上编写代码的绝佳解决方案-它显然非常正确,并且很难编写错误。您也可以使用LIINQ- Enumerable.Range(int.MinValue, int.MaxValue).First(i => i.ToString() == stringValue
a安

0

任何乘法都可以用重复加法代替。因此,您可以将现有算法中的任何乘法替换为仅使用加法的版本:

static int Multiply(int a, int b)
{
    bool isNegative = a > 0 ^ b > 0;
    int aPositive = Math.Abs(a);
    int bPositive = Math.Abs(b);
    int result = 0;
    for(int i = 0; i < aPositive; ++i)
    {
        result += bPositive;
    }
    if (isNegative) {
        result = -result;
    }
    return result;
}

您可以更进一步,并使用此想法将专用的String编写为Int,以最大程度减少增加的数量(为简便起见,省略了负数和错误处理):

static int StringToInt(string v)
{
    const int BASE = 10;
    int result = 0;
    int currentBase = 1;
    for (int digitIndex = v.Length - 1; digitIndex >= 0; --digitIndex)
    {
        int digitValue = (int)Char.GetNumericValue(v[digitIndex]);
        int accum = 0;
        for (int i = 0; i < BASE; ++i)
        {
            if (i == digitValue)
            {
                result += accum;
            }
            accum += currentBase;
        }
        currentBase = accum;
    }
    return result;
}

但是我认为这不值得麻烦,因为在这里性能似乎并不是问题。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.