Запоминание динамического программирования

Я пытаюсь изучить мемоизацию динамического программирования, и я смотрел видео на YouTube из Массачусетского технологического института, пытаясь следовать за ним. Я не знаю, как сравнить N-е значение с массивом.

int[] memo;
public int fib(int n) {
    int f = 0;

    if n is in memo then return memo[n] <----not sure how to code this line.

    if (n<=2) {
        f = 1;
    } else {
        f = fib(n-1) + fib(n-2);
    }

    memo[n] = f;
    return f;
}

person JavaStudent    schedule 17.02.2013    source источник
comment
вам разрешено использовать java API ??   -  person PermGenError    schedule 17.02.2013
comment
Обратите внимание, что эта концепция называется запоминание (без r). Я отредактировал ваш вопрос соответственно.   -  person stakx - no longer contributing    schedule 17.02.2013


Ответы (5)


Делаем это с ArrayList:

ArrayList<Integer> memo = new ArrayList<Integer>();

public int fib(int n) {
    if (memo.size() == 0)
       memo.add(0); // element 0 is never accessed
    return fib2(n);
}

private int fib2(int n) {
    int f = 0;

    if (n < memo.size())
       return memo.get(n);

    if (n<=2) {
        f = 1;
    } else {
       f = fib2(n-2) + fib2(n-1);
    }

    memo.add(f); // elements inserted in order
    return f;
}

Делаем это с массивом:

int[] memo;

public int fib(int n) {
    memo = new int[n+1]; // all initialized to 0
    return fib2(n);
}

private int fib2(int n) {
    int f = 0;

    if (memo[n] != 0)
       return memo[n];

    if (n <= 2) {
        f = 1;
    } else {
        f = fib2(n-2) + fib2(n-1);
    }

    memo[n] = f;
    return f;
}
person Bernhard Barker    schedule 17.02.2013
comment
Я получаю сообщение об ошибке с nullPointerException с вашим массивом. Для массива число выходит не сразу после fib (5). - person JavaStudent; 17.02.2013
comment
@JavaStudent Для массива - у вас, вероятно, не было второй функции, такой как fib выше, которая создает memo и вызывает исходную функцию. Для ArrayList - Кажется, на моей машине печатается правильно. Вы проверили значения должно быть? - person Bernhard Barker; 17.02.2013
comment
Хорошо, я вижу, где мой номер ошибся. Если бы я не добавил memo.add(0), то после fib(6) число прыгало бы с 1,1,2,3,5,7,19,21,50. Зачем нам нужно добавить (0), если мы не собираемся его использовать? - person JavaStudent; 17.02.2013
comment
@JavaStudent Потому что memo.get(n) = fib(n)fib(0) равно 0, но никогда не вычислялось и не использовалось с этим алгоритмом). Можно также удалить memo.add(0) и получить memo[n-1] = fib(n) (с соответствующими изменениями). - person Bernhard Barker; 17.02.2013
comment
В ваших кодах отсутствует оператор return в определении fib (у вас должен быть return fib2(n);). А код с array объявляет массив недостаточно большим (он должен быть размером n+1, а не только n). - person Clément; 02.02.2017

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

Таким образом, проверка того, был ли уже вставлен memo[i], означает, что вы должны проверить, был ли memo[i] != -1.

Примечание: на самом деле эта концепция называется запоминание

person Jean Logeart    schedule 17.02.2013
comment
Почему бы просто не оставить значение по умолчанию 0? Ни одно инициализированное значение в массиве никогда не будет равно 0. - person Bernhard Barker; 17.02.2013
comment
Вы можете использовать Arrays.fill для этого. - person Boris the Spider; 17.02.2013
comment
@Dukeling, вы можете оставить 0, но обычно вы активно устанавливаете фиктивное значение, даже если это значение равно 0, чтобы не было двусмысленности. Это особенно полезно, если в вашем алгоритме есть ошибка или вы забыли шаг. - person Jean Logeart; 17.02.2013

Вы не можете сравнить массив с одним элементом.

Что вы, вероятно, хотите, предположим, что у вас есть фиктивное значение -1 для невычисленных значений:

if (memo[n] != -1) return memo[n]

person Javier Villa    schedule 17.02.2013

Мне нравится использовать HashMap для Java. По моему опыту, HashMap делает мемоизацию действительно простой в реализации. https://docs.oracle.com/javase/7/docs/api/java/util/HashMap.html

Четыре шага:

  1. Получить базовый случай

  2. Использование m.get(n) == null для проверки того, была ли вычислена подзадача.

  3. Если (2) неверно, вычислите его рекурсивно и сохраните в HashMap.

    Ключ HashMap – это идентификатор текущей подзадачи (в случае Фибоначчи это n n-й Последовательность Фибоначчи. значение – это рекурсивный вызов, решающий нерешенную проблему.

  4. Если (2) верно, вернуть m.get(n).

Вот пример Фибоначчи, использующий 4 шага:

HashMap<Integer, Integer> memo = new HashMap<Integer,Integer>();

int fib(int n) {

    //1. base case
    if (n <= 1) 
        return n; 

    //2. check if sub problem is computed yet.
    if (m.get(n) == null) {

        //3. if not, compute the sub problem.
        m.put(n, fib(n - 1) + fib(n - 2));
    }

    //4. if so, return the result. 
    return m.get(n); 
}

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

person Han Sheng Huang    schedule 20.01.2016

Как ни странно, у этого вопроса 0 голосов, но 4 ответа, и я не нахожу ни один из них действительно удовлетворительным. Вот пример реализации + тест с использованием 4 разных методов и их сравнение:

import java.util.ArrayList;
import java.util.HashMap;

public class Fib {

    // Straightforward implementation:
    public static int fib(int n) {
    if (n <= 1) {
        return n;
    }
    return fib(n - 1) + fib(n - 2);
    }

    // Using array:
    static int[] memoArray;
    public static int fibArray(int n) {
    memoArray = new int[n];
    return fibArrayHelper(n);
    }
    private static int fibArrayHelper(int n) {
    if (n <= 1) {
        return n;
    } else {
        if (memoArray[n - 2] != 0) {
        return memoArray[n - 2];
        }
        memoArray[n - 2] = fibArrayHelper(n - 2) + fibArrayHelper(n - 1);
        return memoArray[n - 2];
    }
    }

    // Using ArrayList:
    static ArrayList < Integer > memoArrayList = new ArrayList < Integer > ();

    public static int fibArrayList(int n) {
    return fibArrayListHelper(n);
    }

    private static int fibArrayListHelper(int n) {
    if (n <= 1) {
        return n;
    } else {
        if (n - 2 < memoArrayList.size())
        return memoArrayList.get(n - 2);
        else {
        memoArrayList.add(fibArrayListHelper(n - 2) + fibArrayListHelper(n - 1));
        return memoArrayList.get(n - 2);
        }
    }
    }

    // Using HashMap:
    static HashMap < Integer, Integer > memoHash = new HashMap < Integer, Integer > ();

    static public int fibHashMap(int n) {
    if (n <= 1)
        return n;
    if (memoHash.get(n) == null) {
        memoHash.put(n - 2, fibHashMap(n - 1) + fibHashMap(n - 2));
    }
    return memoHash.get(n - 2);
    }


    public static void main(String args[]) {
    long preTime, postTime;
    int x = 35;

    preTime = System.nanoTime();
    System.out.printf("%17s: %d", "fib(" + x + ")", fib(x));
    postTime = System.nanoTime();
    System.out.printf(", computed in %10d nanoseconds.\n", postTime - preTime);

    preTime = System.nanoTime();
    System.out.printf("%17s: %d", "fibArray(" + x + ")", fibArray(x));
    postTime = System.nanoTime();
    System.out.printf(", computed in %10d nanoseconds.\n", postTime - preTime);

    preTime = System.nanoTime();
    System.out.printf("%17s: %d", "fibArrayList(" + x + ")", fibArrayList(x));
    postTime = System.nanoTime();
    System.out.printf(", computed in %10d nanoseconds.\n", postTime - preTime);

    preTime = System.nanoTime();
    System.out.printf("%17s: %d", "fibHashMap(" + x + ")", fibHashMap(x));
    postTime = System.nanoTime();
    System.out.printf(", computed in %10d nanoseconds.\n", postTime - preTime);
    }
}
person Clément    schedule 02.02.2017