【问题标题】:Converting String to Integer without using Multiplication C#在不使用乘法 C# 的情况下将字符串转换为整数
【发布时间】:2020-05-06 06:02:50
【问题描述】:

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

【问题讨论】:

  • 带(文本)还是不带(标题)?
  • 你能澄清一下吗?你的标题说“不使用”,而你的文字说“有”使用......
  • 考虑到问题的其余内容(例如“但这也需要将数字乘以它的底数 10”),标题是正确的。另外,如果允许乘法,那么这是微不足道的,所以问它是没有意义的。
  • this article 建议用位移和加法 (x<<1 + x<<3) 替换乘以 10,但这仍然是使用乘法的一种方式,因此很难说这是否符合问题...
  • for (int i = 0; i < 10; i++) result += number; 算不算?

标签: c# string int


【解决方案1】:

如果您假设一个基数为 10 的数字系统并用位移来代替乘法 (see here),这可能是正整数的解决方案。

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' 将数字字符转换为其整数值。

编辑:

对于负整数,此版本 (see here) 有效。

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;
}

一般来说,您应该将错误考虑在内,例如空检查、其他非数字字符的问题等。

【讨论】:

    【解决方案2】:

    这取决于。我们是在谈论乘法的逻辑运算,还是它在硬件中实际是如何完成的?

    例如,您可以将十六进制(或八进制,或任何其他以 2 为底的乘数)字符串转换为“不带乘法”的整数。您可以逐个字符地继续进行 oring (|) 和位移 (&lt;&lt;)。这避免了使用* 运算符。

    对十进制字符串做同样的事情比较棘手,但我们仍然有简单的加法。您可以使用带有加法的循环来做同样的事情。做起来很简单。或者你可以制作自己的“乘法表”——希望你在学校学会了如何乘法;你可以用电脑做同样的事情。当然,如果您使用的是十进制计算机(而不是二进制),您可以执行“位移”,就像之前的十六进制字符串一样。即使使用二进制计算机,您也可以使用一系列位移 - (a &lt;&lt; 1) + (a &lt;&lt; 3)a * 2 + a * 8 == a * 10 相同。小心负数。你可以想出很多技巧来让这件事变得有趣。

    当然,这两者都只是变相的乘法。这是因为位置数值系统本质上是乘法。这就是特定数字表示的工作方式。您可以进行简化来隐藏这一事实(例如,二进制数只需要01,因此您可以有一个简单的条件,而不是相乘 - 当然,你真正在做的仍然是乘法,只有两个可能的输入和两个可能的输出),但它总是在那里,潜伏着。 &lt;&lt;* 2 相同,即使执行操作的硬件可以更简单和/或更快。

    要完全取消乘法,您需要避免使用位置系统。例如,罗马数字是加法的(请注意,实际的罗马数字没有使用我们今天的紧缩规则——四个是IIII,而不是IV,它十四可以写成任何形式,比如XIIIIIIIIXIIXIIVVIIII 等)。将这样的字符串转换为整数变得非常容易 - 只需逐个字符,然后继续添加。如果字符是X,则加十。如果V,加五。如果I,则加一。我希望你能明白为什么罗马数字流行了这么久;当您需要进行大量乘法和除法运算时,位置数字系统非常有用。如果您主要处理加法和减法,罗马数字效果很好,而且需要的教育少得多(而且算盘比位置计算器更容易制作和使用!)。

    对于这样的作业,面试官的实际期望会受到很多影响。也许他们只是想看看你的思维过程。你接受技术性(&lt;&lt; 不是真的乘法)?你知道数论和计算机科学吗?您只是继续编写代码,还是要求澄清?你认为这是一个有趣的挑战,还是又一个与你的工作无关的荒谬无聊的面试问题?我们不可能告诉你面试官想要的答案。

    但我希望我至少让你看到了可能的个答案:)

    【讨论】:

    • 如果我们使用罗马数字系统,如果我们有 B、T、S、R、G、A 等不属于罗马数字系统的字符,您将如何添加。换句话说,如何获得 int 等价物?
    • @Adheesh 我不知道你想问什么。你能举一个你认为有问题的例子吗?
    • 假设我们有一个字符串“12345”,我们想把它转换成一个int。如果我不想使用位置数字系统而是使用罗马数字系统怎么办。我们怎么能做到呢? (我根本不想使用乘法)
    • @Adheesh 在罗马数字系统中,字符串不会是“12345”。这就是重点。位置数值系统本质上是乘法的。罗马数字系统是加法的。罗马字符串类似于“MMMMMMMMMMMMCCCXXXXIIIII”。逐个字符,不断添加数字。
    • @Adheesh 当然,在实际实际中,不会有这么长的笨拙的混乱。而不是“12345 米”,您会说“XII 公斤和 CCCXXXXIIIII 米”之类的东西。旧的测量系统适用于无法计数的人 - 如果您只能数到十二,只需将您可以用英制单位表示的值范围与现代单位进行比较:)
    【解决方案3】:

    考虑到这是一个面试问题,性能可能不是一个高优先级。为什么不只是:

    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.
    }
    

    如果传入的字符串不是整数,该方法会抛出溢出异常。

    【讨论】:

    • Brilliant :P 如果没有面试官的即时反馈,请确保你不要使用它,尽管 :DI 想象甚至可能有一些方法可以通过部分匹配来提高性能,使用相同的基本方法。至少,对负数的简单检查可以为您节省一半的循环;检查奇数/偶数的另一半。
    • @Luaan 我想用尽可能少的线条来完成它:) ... public int StringToInt(string value, int search_from = int.MinValue) =&gt; value == search_from.ToString() ? search_from : StringToInt (value, ++search_from);
    • 可悲的是,这会爆炸 :D 但这是在纸上编写代码的绝佳解决方案 - 它非常明显地正确,而且很难写错。你也可以使用 LIINQ - Enumerable.Range(int.MinValue, int.MaxValue).First(i =&gt; i.ToString() == stringValue
    【解决方案4】:

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

    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;
    }
    

    你可以更进一步,使用这个想法为 Int 编写一个专门的 String ,这样可以最大限度地减少加法的数量(为简洁起见,省略了负数和错误处理):

    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;
    }
    

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

    【讨论】:

      猜你喜欢
      • 2011-04-28
      • 1970-01-01
      • 2012-08-02
      • 2012-05-12
      • 2013-06-04
      • 2019-07-19
      • 1970-01-01
      • 2013-06-04
      • 1970-01-01
      相关资源
      最近更新 更多