Javaでパワーメソッドを書かなければなりません。 2つの整数を受け取り、それらが正の数であるか負の数であるかは関係ありません。 O(logN)
の複雑さを持っている必要があります。また、再帰を使用する必要があります。私の現在のコードは2つの数値を取得しますが、出力し続ける結果はゼロであり、その理由を理解できません。
import Java.util.Scanner;
public class Powers {
public static void main(String[] args) {
float a;
float n;
float res;
Scanner in = new Scanner(System.in);
System.out.print("Enter int a ");
a = in.nextFloat();
System.out.print("Enter int n ");
n = in.nextFloat();
res = powers.pow(a, n);
System.out.print(res);
}
public static float pow(float a, float n) {
float result = 0;
if (n == 0) {
return 1;
} else if (n < 0) {
result = result * pow(a, n + 1);
} else if (n > 0) {
result = result * pow(a, n - 1);
}
return result;
}
}
いくつかの数学の事実から始めましょう:
正のnケースから始めて、そこから作業しましょう。
ソリューションを再帰的にしたいので、小さいnに基づいてaⁿを定義し、そこから作業する方法を見つける必要があります。再帰について考える一般的な方法は、n-1の解決策を見つけてそこから作業することです。
実際、aⁿ=a⨯(aⁿ⁻¹)であることは数学的に真実であるため、単純なアプローチは作成したものと非常に似ています。
_public static int pow( int a, int n) {
if ( n == 0 ) {
return 1;
}
return ( a * pow(a,n-1));
}
_
ただし、これの複雑さはO(n)です。どうして? n = 0の場合、乗算は行われません。 n = 1の場合、1つの乗算を行います。 n = 2の場合、1回の乗算であることがわかっているpow(a、1)を呼び出し、1回乗算するため、2回の乗算があります。すべての再帰ステップで1つの乗算があり、nステップあります。つまり、O(n)です。
このO(log n)を作成するには、n-1だけでなく、nのfractionにすべてのステップを適用する必要があります。ここでも、私たちを助けることができる数学の事実があります:an₁+n₂ = an₁⨯an₂。
これは、aⁿをaとして計算できることを意味しますn/2⨯an/2。
しかし、nが奇数の場合はどうなりますか? a⁹のようなものは4.5⨯a4.5。しかし、ここでは整数のべき乗について話しています。分数の扱いはまったく異なります。幸い、私たちはそれをa⨯a⁴⨯a⁴として定式化できます。
したがって、偶数の場合はn/2⨯an/2、奇数の場合はa⨯aを使用しますn/2⨯an/2 (整数除算、9/2 = 4を与えます)。
_public static int pow( int a, int n) {
if ( n == 0 ) {
return 1;
}
if ( n % 2 == 1 ) {
// Odd n
return a * pow( a, n/2 ) * pow(a, n/2 );
} else {
// Even n
return pow( a, n/2 ) * pow( a, n/2 );
}
}
_
これにより、実際には正しい結果が得られます(nが正の場合)。しかし、実際、ここでの複雑さは、ここでも、O(log nではなくO(n))です。なぜですか?パワーを2回計算しているためです。実際にそれを4と呼ぶことを意味します。再帰ステップの数は指数関数的であるため、これは、nを2で除算することによって行った節約と相殺されます。
しかし、実際には、ほんの少しの修正が必要です:
_public static int pow( int a, int n) {
if ( n == 0 ) {
return 1;
}
int powerOfHalfN = pow( a, n/2 );
if ( n % 2 == 1 ) {
// Odd n
return a * powerOfHalfN * powerOfHalfN;
} else {
// Even n
return powerOfHalfN * powerOfHalfN;
}
}
_
このバージョンでは、再帰を1回だけ呼び出しています。したがって、たとえば64の累乗から、32、16、8、4、2、1を非常に迅速に取得して完了します。各ステップで1つまたは2つの乗算のみで、6つのステップしかありません。これはO(log n)です。
このすべてからの結論は次のとおりです。
最後に、負の数を処理する準備が整いました。逆数の⅟a⁻ⁿを取得するだけです。注意すべき重要な点が2つあります。
throws
句を追加する必要はありません。引数を読み取るときにmain
メソッドで、それをキャッチするか、そのような状況が発生しないようにするとよいでしょう。long
を使用して整数のオーバーフローが発生するため、int
を使用する必要がありました)-結果が小数になる可能性があるためです。したがって、メソッドがdoubleを返すように定義します。つまり、powerOfHalfN
のタイプも修正する必要があります。そしてここに結果があります:
_public static double pow(int a, int n) {
if (n == 0) {
return 1.0;
}
if (n < 0) {
// Negative power.
if (a == 0) {
throw new IllegalArgumentException(
"It's impossible to raise 0 to the power of a negative number");
}
return 1 / pow(a, -n);
} else {
// Positive power
double powerOfHalfN = pow(a, n / 2);
if (n % 2 == 1) {
// Odd n
return a * powerOfHalfN * powerOfHalfN;
} else {
// Even n
return powerOfHalfN * powerOfHalfN;
}
}
}
_
負のnを処理する部分は、再帰の最上位でのみ使用されることに注意してください。 pow()
を再帰的に呼び出すと、常に正の数になり、符号は0に達するまで変化しません。
それはあなたの運動への適切な解決策になるはずです。ただし、個人的には最後のif
が気に入らないので、ここに別のバージョンがあります。これが同じことをしている理由がわかりますか?
_public static double pow(int a, int n) {
if (n == 0) {
return 1.0;
}
if (n < 0) {
// Negative power.
if (a == 0) {
throw new IllegalArgumentException(
"It's impossible to raise 0 to the power of a negative number");
}
return 1 / pow(a, -n);
} else {
// Positive power
double powerOfHalfN = pow(a, n / 2);
double[] factor = { 1, a };
return factor[n % 2] * powerOfHalfN * powerOfHalfN;
}
}
_
注意を払う :
float result = 0;
そして
result = result * pow( a, n+1);
そのため、結果はゼロです。代わりに、次のように動作することが推奨されています。
result = a * pow( a, n+1);
result
を0に初期化するエラーのほかに、いくつかの問題があります。
n
の計算が間違っています。 a^n == 1/(a^(-n))
を思い出してください。O(log n)
のパフォーマンスを実現するには、分割統治戦略を使用する必要があります。つまり、a^n == a^(n/2)*a^(n/2)
です。これは、少なくとも余分な乗算について心配していない場合は、これを行う方法の混乱が少ない方法です。 :
public static double pow(int base,int exponent) {
if (exponent == 0) {
return 1;
}
if (exponent < 0) {
return 1 / pow(base, -exponent);
}
else {
double results = base * pow(base, exponent - 1);
return results;
}
}
import Java.io.*;
import Java.util.*;
public class CandidateCode {
public static void main(String args[] ) throws Exception {
Scanner sc = new Scanner(System.in);
int m = sc.nextInt();
int n = sc. nextInt();
int result = power(m,n);
System.out.println(result);
}
public static int power(int m, int n){
if(n!=0)
return (m*power(m,n-1));
else
return 1;
}
}
これを試して:
public int powerN(int base, int n) {return n == 0 ? 1 : (n == 1 ? base : base*(powerN(base,n-1)));
適切な規則は、アルゴリズムの準備ができるまでキーボードから離れることです。あなたがしたことは明らかにO(n)です。
Eranが提案したように、O(log(n))の複雑さを得るには、各反復でnを2で除算する必要があります。
終了条件:
特別なケース :
通常の場合:
このアルゴリズムはO(log(n))にあります-正しいJavaからコードを書くのはあなた次第です
しかし、あなたが言われたように:n must整数であること(正のokの負、ただしinteger)