Рекурсивный метод для x^n оптимизирован для четного

мне нужно написать рекурсивный метод с использованием Java под названием power, который принимает двойное x и целое число n и возвращает x^n. Вот что у меня пока есть.

public static double power(double x, int n) {
    if (n == 0)
        return 1;
    if (n == 1)
        return x;
    else
        return x * (power(x, n-1));

}

этот код работает, как ожидалось. Тем не менее, я пытаюсь пройти лишнюю милю и выполнить следующее дополнительное упражнение:

" необязательный вызов: вы можете сделать этот метод более эффективным, когда n четный, используя x^n = (x^(n/2))^2."

Я не уверен, как реализовать эту последнюю формулу, когда N четно. Я не думаю, что могу использовать для этого рекурсию. Я попытался реализовать следующее, Но это также не работает, потому что я не могу взять двойной силой int.

if (n%2 == 0)
        return (x^(n/2))^2;

может кто-нибудь указать мне в правильном направлении? Мне кажется, я упускаю что-то очевидное. Все это поможет по достоинству.

6 ответов


это точно такой же принцип, как и для x^n == x*(x^(n-1)): Вставьте рекурсивную функцию для x^(n/2) и (...) ^2, но убедитесь, что вы не вводите бесконечную рекурсию для n == 2 (так как 2 тоже четное):

if (n % 2 == 0 && n > 2) 
  return power(power(x, n / 2), 2);
} 

кроме того, вы можете просто использовать промежуточную переменную:

if (n % 2 == 0) {
  double s = power(x, n / 2);
  return s * s;
}

Я бы, вероятно, просто обработал 2 как особый случай, тоже-и избежать"и" -условие и дополнительная переменная:

public static double power(double x, int n) {
  if (n == 0) return 1;
  if (n == 1) return x;
  if (n == 2) return x * x;
  if (n % 2 == 0) return power(power(x, n / 2), 2);
  return x * (power(x, n - 1));
}

P. S. Я думаю, что это должно работать, тоже :)

public static double power(double x, int n) {
  if (n == 0) return 1;
  if (n == 1) return x;
  if (n == 2) return x * x;
  return power(x, n % 2) * power(power(x, n / 2), 2);
}

, когда n является четным, формула именно то, что вы написали: divide n два, называть power рекурсивно и Квадрат результата.

, когда n нечетно, формула немного сложнее: вычесть 1 С n сделать рекурсивный вызов для n/2, квадрат результата и умножить на x.

if (n%2 == 0)
    return (x^(n/2))^2;
else
    return x*(x^(n/2))^2;

n/2 усекает результат, поэтому вычитание 1 не выполняется явно. Вот реализация в Java:

public static double power(double x, int n) {
    if (n == 0) return 1;
    if (n == 1) return x;
    double pHalf = power(x, n/2);
    if (n%2 == 0) {
        return pHalf*pHalf;
    } else {
        return x*pHalf*pHalf;
    }
}

демо.


Подсказка:^ операция не будет выполнять возведение в степень на Java, но функция, которую вы написали,power будет.

кроме того, не забывайте, что возведение в квадрат числа-это то же самое, что просто умножение его на себя. Вызов функции не требуется.


сделав небольшое изменение в вашей функции, это уменьшит количество рекурсивных вызовов:

public static double power(double x, int n) {
    if (n == 0) {
        return 1;
    }
    if (n == 1) {
        return x;
    }

    if (n % 2 == 0) {
        double temp = power(x, n / 2);
        return temp * temp;
    } else {
        return x * (power(x, n - 1));
    }
}

С

x^(2n) = (x^n)^2

вы можете добавить это правило в свой метод, используя либо написанную вами степенную функцию, как предложил Стефан Хаустейн, либо используя обычный оператор умножения, поскольку, похоже, вам разрешено это делать.

обратите внимание, что нет необходимости в обоих базовых случаях n=1 и n=0, одного из них достаточно (предварительно используйте базовый случай n=0, так как в противном случае ваш метод не будет определен для n=0).

public static double power(double x, int n) {
    if (n == 0)
        return 1;
    else if (n % 2 == 0)
        double val = power(x, n/2);
        return val * val;
    else
        return x * (power(x, n-1));
}

нет необходимости проверять, что N>2 в любом из случаев.


Это просто напоминает мне, что можно было бы сделать больше оптимизации и это следующий код.

class Solution:
# @param x, a float
# @param n, a integer
# @return a float
def pow(self, x, n):
    if n<0:
        return 1.0/self.pow(x,-n)
    elif n==0:
        return 1.0
    elif n==1:
        return x
    else:
        m = n & (-n)
        if( m==n ):
            r1 = self.pow(x,n>>1)
            return r1*r1
        else:
            return self.pow(x,m)*self.pow(x,n-m)

что более промежуточный результат можно запомнить и избежать избыточных вычислений.