有没有一种方法可以将字符串转换为整数而不使用乘法。int.Parse()的实现也使用乘法。我还有其他类似的问题,您可以在其中手动将字符串转换为int,但这还需要将数字乘以10为底。这是我在一次采访中遇到的一个采访问题,我似乎找不到任何答案。
for (int i = 0; i < 10; i++) result += number;
算?
有没有一种方法可以将字符串转换为整数而不使用乘法。int.Parse()的实现也使用乘法。我还有其他类似的问题,您可以在其中手动将字符串转换为int,但这还需要将数字乘以10为底。这是我在一次采访中遇到的一个采访问题,我似乎找不到任何答案。
for (int i = 0; i < 10; i++) result += number;
算?
Answers:
如果您假设以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;
}
通常,您应该考虑错误,例如空检查,其他非数字字符的问题等。
这取决于。我们是在谈论乘法的逻辑运算,还是在硬件中的实际运算方式?
例如,您可以将十六进制(或八进制,或任何其他基数为2的乘法器)字符串转换为整数“无乘法”。您可以逐个字符并保持或(|
)和移位(<<
)。这避免了使用*
运算符。
对十进制字符串执行相同的操作比较棘手,但是我们仍然有简单的加法运算。您可以使用添加循环来完成相同的操作。做起来很简单。或者,您可以制作自己的“乘法表”-希望您在学校学习了如何对数字进行乘法;您可以使用计算机执行相同的操作。当然,如果您使用的是十进制计算机(而不是二进制计算机),则可以执行“ bitshift”操作,就像使用较早的十六进制字符串一样。即使使用二进制计算机,您也可以使用一系列移位- (a << 1) + (a << 3)
与相同a * 2 + a * 8 == a * 10
。小心负数。您可以找出很多使这个有趣的技巧。
当然,这两个都是变相的乘积。那是因为位置数字系统本质上是乘法的。这就是特定数字表示的工作方式。您可以使用隐藏此事实的简化方法(例如,仅需要0
和的二进制数)1
,因此您可以有一个简单的条件,而不是相乘-当然,您实际上所做的仍然是相乘,只有两个可能的输入和两个可能的输出),但它一直都在潜伏着。<<
与相同* 2
,即使执行该操作的硬件可以更简单和/或更快速。
要完全消除乘法,您需要避免使用位置系统。例如,罗马数字是累加的(请注意,实际的罗马数字没有用我们今天的紧凑化规则-四会IIII
,不IV
,这14可以在任何形式的像写XIIII
,IIIIX
,IIXII
,VVIIII
等)。将这样的字符串转换为整数变得非常容易-逐个字符并继续添加。如果字符是X
,则添加十。如果为V
,则添加五个。如果I
,添加一个。我希望您能理解为什么罗马数字在这么长的时间内仍然很流行。当您需要进行很多乘法和除法运算时,位置数值系统非常有用。如果您主要处理加法和减法,则罗马数字的效果很好,并且不需要太多的教育(并且算盘比位置计算器更容易制造和使用!)。
有了这样的作业,面试官的实际期望会受到很多折磨。也许他们只是想看看您的思维过程。您是否接受技术性(<<
不是真正的乘法)?你知道数论和计算机科学吗?您只是沉迷于代码,还是要求澄清?您认为这是一个有趣的挑战,还是另一个荒谬而无聊的面试问题,与您的工作无关?我们不可能告诉您面试官正在寻找的答案。
但我希望至少能给您带来一些可能的答案:)
考虑到这是一个面试问题,表现可能不是头等大事。为什么不只是:
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.
}
如果传递的字符串不是整数,则该方法将引发溢出异常。
public int StringToInt(string value, int search_from = int.MinValue) => value == search_from.ToString() ? search_from : StringToInt (value, ++search_from);
Enumerable.Range(int.MinValue, int.MaxValue).First(i => i.ToString() == stringValue
。
任何乘法都可以用重复加法代替。因此,您可以将现有算法中的任何乘法替换为仅使用加法的版本:
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;
}
但是我认为这不值得麻烦,因为在这里性能似乎并不是问题。