剣はオファー質問17を指します-値の整数乗

整数の累乗

トピック:数値nを入力し、1から最大のn桁までの10進数を順番に出力します。たとえば、3を入力すると、1、2、3は最大の3桁の数字999まで印刷されます。

1.
一見したところ落とし穴、それは非常に単純に見えます、それは1つのループで行うことができます

void PrintToMaxOfNDigits_1(int n)
{
    
    
	int number=1;
	int i=0;
	while(i++<n)
		number*=10;
	
	for(i=1;i<number;++i)
		print("%d\t",i);
}

しかし、よく考えてみると、nの範囲がないので、nが大きい場合は、整数(int)でも長整数(long long)でもオーバーフローします。

だから実際にはこれは大きな問題です!
多数の問題は何ですか?
もちろんそうです-ひも!

2.文字列のデジタル加算をシミュレートします。
最大数はn桁であるため、長さがn + 1の文字列が必要です(文字列の最も一般的な桁は\ 0です)。実際の数が十分でない場合n最後、文字列の前半に0を追加します。
まず、文字列の各桁を「0」に初期化します。次に、文字列で表される数値に毎回1を加算して、出力します。したがって、2つのことを行うだけで済みます。1つは文字列で表される数値にアナログを追加すること、もう1つは文字列で表される数値を出力することです。
上記の考え方によれば、次のコードがあります。

void PrintToMaxOfNDigits(int n)
{
    
    
	if(n<=0)
		return;
	char* number=new char[n+1];
	memset(number,'0',n);
	number[n]='\0';
	
	while(!Increment(number))
	{
    
    
		PrintNumber(number);
	}
	delete []number;
}

その中で、関数Incrementは、1ずつ増加した数値文字列番号を表し、関数PrintNumberは、数値を出力するためのものです。

ここで重要なのは、2つの関数を作成することです。

a。Increment関数
は、数値の1ずつの増加を停止するタイミングをどのように認識しますつまり、最大n桁の「9999 ... 999」に達したときに、増加するたびにstrcmp関数を呼び出して、文字列を比較します。 「9999 ... 999」が最大の数値。strcmpの呼び出しは簡単ですが、答えは、長さnの文字列の場合、複雑さはO(n)です。
もっと良い方法はありますか?もちろん、「999 ... 999」に1を加えた場合のみ、最初の文字(添え字は0)に基づいてキャリーが生成されることがわかります。このとき、これは最大のn桁の数値です。このとき、Incrementはtrueを返し、ループは停止します。
コードは次のように表示されます。

bool Increment(char* number)
{
    
    
	bool isOverflow=false;
	int nTakeOver=0;
	int nLength=strlen(number);
	for(int i=nLength-1;i>=0;i--)
	{
    
    
		int nSum=number[i]-'0'+nTakeOver;
		if(i==nLength-1)
			nSum++;
		if(nSum>=10)
		{
    
    
			if(i==0)
				isOverflow=true;
			else
			{
    
    
				nSum-=10;
				nTakeOver=1;
				number[i]='0'+nSum;
			}
		}
		else
		{
    
    
			number[i]='0'+nSum;
			break;
		}
	}
	return isOverflow;
}

a.PrintNumber関数
桁数が足りない場合は、数字の前に0を付けますが、印刷時には印刷しないので、最初のゼロ以外のときに印刷する必要があります。

void PrintNumber(char* number)
{
    
    
	bool isBeginning=true;
	int nLength=strlen(number);
	for(int i=0;i<nLength;++i)
	{
    
    
		if(isBeginning && number[i]!='0')
			isBeginning=false;
		
		if(!isBeginning)
		{
    
    
			printf("%c",number[i]);
		}
	}
	printf("\t");
}

3.再帰により、コードがより簡潔になります。
数値の前に0を追加すると、n桁のすべての10進数が、実際には0から9までの時間で完全に配置されていることがわかります。つまり、0から9までの数字の各桁を配置し、すべての10進数を取得します。印刷時に最初の0が印刷されないだけです。
完全な配置は簡単に表現できます。数字の各桁は0から9までの数字で、次の桁を設定できます。再帰的な終了条件が次の場合番号の最後の桁を設定します。

void PrintToMaxOfNDigits(int n)
{
    
    
	if(n<=0)
		return;
	char* number=new char[n+1];
	number[n]='\0';
	
	for(int i=0;i<10;++i)
	{
    
    
		number[0]=i+'0';
		PrintToMaxOfNDigitdRecursively(number,n,0);
	}
	delete[] number;
}

void PrintToMaxOfNDigitdRecursively(char* number,int length,int index)
{
    
    
	if(index==length-1)
	{
    
    
		PrintNumber(number);
		return;	
	}
	for(int i=0;i<10;++i)
	{
    
    
		number[index+1]=i+'0';
		PrintToMaxOfNDigitdRecursively(number,length,index+1);
	}
}

参考書:「ソードフィンガーオファー」

おすすめ

転載: blog.csdn.net/rjszz1314/article/details/104175150