[Sword Finger Offer]-特定のライブラリ関数pow、atoiを実装

インタビューの質問では、数値や文字列を処理するための関数がよくありますが、この記事では主にpow and atoi関数の実装について説明します〜

1つは、pow関数

トピックの要件

関数double Power(double base、int exponent)を実装し、baseの指数指数を求めます。ライブラリ関数を使用しないでください。また、多数を考慮する必要はありません。

トピック分析

多数の問題を考慮する必要がないため、まずこの問題が発生すると、私たちの頭脳から生まれたアイデアは次のように実現されます。

double Power(double base, int exponent)
{
	double result = 0;
	for (int i = 0; i <= exponent; i++)
	{
		result *= base;
	}
	return result;
}

しかし、このように書くのは間違いです。多くの欠点があります

改善1:底が0で指数が負の
場合を考えるこのような特殊なケースのため、エラー処理の方法を考慮する必要があります。
私たちが作成するプログラムには、通常3つのエラー処理方法があります。以下に、対応する長所と短所を示します
ここに画像の説明を挿入
。改善されたコードは次のとおりです。

bool g_InvalidInput = false;

double Power(double base, int exponent)
{
	g_InvalidInput = false;

	if (equal(base, 0.0) && exponent < 0)
	{
		g_InvalidInput = true;
		return 0.0;
	}

	unsigned int absExponent = (unsigned int)(exponent);
	if(exponent < 0)
		absExponent = (unsigned int)(-exponent);

	double result = Powerresult(base, absExponent);
	if (exponent < 0)
		result = 1.0 / result;
	return result;
}		

上記のコードでは、グローバル変数を使用して、問題が発生したかどうかを識別しています。問題が発生した場合、返される値は0です。ただし、エラーが発生したときに0を返すのか、ベースが0のときに0に戻るのかを区別するために、区別するためにg_InvalidInputグローバル変数を設計しました。エラーが発生すると、この変数はtrueに設定され、それ以外の場合はfalseに設定されます。

改善2:より効率的なPowerresultメソッド
入力指数が32の場合、前のループでは31ループを実行する必要がありますが、慎重に考えると、より簡潔なメソッドがあるようです。
ここでは、フィボナッチシーケンスで言及したソリューションについて説明します。フィボナッチ列に数式を使用する方法があります。その時間の複雑さはO(logn)です。パワーを考慮した数式は次のとおりです。
ここに画像の説明を挿入
上記の数式から、メソッドをn倍改善したいことがわかります。二乗、最初にn / 2乗を取得し、次にn / 2乗の結果を二乗する必要があります。これは、再帰的なアイデアで実現できます。
フィボナッチ数列の前兆があるため、関数について考えるのは簡単です。私たちは32乗を求めているので、そこから16乗、8乗、4乗、そして2乗を計算します。これから導出される数式は次のとおりです。
ここに画像の説明を挿入
上記の数式に基づいて、コードは次のように実装されます。

double Powerresult(double base, unsigned int exponent)
{
	if (exponent == 0)
		return 1;
	if (exponent == 1)
		return base;

	//递归乘法的过程
	double result = Powerresult(base, exponent >> 1);
	result *= result;

	//指数为奇数的情况
	if ((exponent & 0x1) == 1)
		result *= base;

	return result;
}

2、atoi関数

トピックの要件

文字列を整数に変換します。たとえば、文字列「123」を入力します。彼の出力は数値123です。

トピック分析

まず、この質問を取得します。質問の要件に従って、「123」を数123に変換する場合のみを考えます。しかし、この質問は非常に単純であるだけでなく、そのような状況を考慮するだけでなく、細部まで考慮する必要がある多くの特別な入力状況もあります。

ケース1:文字列が空かどうかを確認する

str != nullptr

ケース2:入力文字列が「0」の場合

ここで、入力した文字列が「0」の場合、戻り値は0になりますが、文字列が空の場合は0の戻り値と競合するため、区別するためにグローバル変数を設定する必要があります。不正な入力の場合は0を返し、グローバル変数を特殊マークとして設定します。入力が文字列 "0"の場合は0を返し、グローバル変数は設定されません。

enum Status{kValid = 0,kInvaild};
int g_nStatus = kValid;

**ケース3:**「0」〜「9」以外のすべての文字が無効であるとは限りません。入力文字列には正負の符号の違いがあるため、プラス記号とマイナス記号も有効な入力である必要があります

if (*str == '+')
   str++;
else if (*str == '-')
{
	str++;
	minus = true;
}

ケース4:最大の正の整数値が0x7FFFFFFFであり、最小の負の整数値が0x80000000であるケースを検討します。

完全なコード実装は次のとおりです
。StrToInt関数を具体的に実装するために2つの関数を分割し、主にそれが有効な入力であるかどうかを判断します。StrToIntCoreは特定の変換のコアコードです

enum Status{kValid = 0,kInvaild};
int g_nStatus = kValid;
long long StrToIntCore(const char* digit, bool minus);

int StrToInt(const char* str)
{
	g_nStatus = kInvaild;
	long long num = 0;

	if (str != nullptr && *str != '\0')//空串判断
	{
		bool minus = false;//设置一个布尔值来保存符号
		//符号判断
		if (*str == '+')
			str++;
		else if (*str == '-')
		{
			str++;
			minus = true;
		}

		//其余字符串转换
		if (*str != '\0')
		{
			num = StrToIntCore(str, minus);
		}
	}
	return (int)num;
}
long long StrToIntCore(const char* digit, bool minus)
{
	long long num = 0;

	while (*digit != '\0')
	{
		if (*digit >= '0' && *digit <= '9')
		{
			int flag = minus ? -1 : 1;
			num = num * 10 + flag * (*digit - '0');//核心代码

			//溢出判断
			if ((!minus && num > 0x7FFFFFFF) || (minus && num < (signed int)0x80000000))
			{
				num = 0;
				break;
			}
			digit++;
		}
		else//非法输入
		{
			num = 0;
			break;
		}
	}
	//输入为'\0'的合法情况
	if (*digit == '\0')
	{
		g_nStatus = kValid;
	}
	return num;
}
公開された98元の記事 ウォンの賞賛9 ビュー3649

おすすめ

転載: blog.csdn.net/qq_43412060/article/details/105403765