Recursion for Catalan number to Memoized

好久不见. 提交于 2020-01-04 05:40:09

问题


I have been asked to write a recursive function that will calculate the Catalan number of monotonic lattice paths along the edges of a grid with n × n square cells, which do not pass above the diagonal (pic)

I was not allowed to use for-loops, only recursive calls... This is what I did:

public long C(int n) {
    if (n == 1)
        return 0;
    return C(n, 0, 0);
}

private long C(int n, int i, int j) {

    // CAN MOVE UP & RIGHT
    if (j - i > 0 && j + 1 <= n)
        return paths(n, i + 1, j) + paths(n, i, j + 1);
    // CAN MOVE UP
    else if (j - i > 0)
        return paths(n, i + 1, j);
    // CAN MOVE RIGHT
    else if (j + 1 <= n)
        return paths(n, i, j + 1);
    // CAN'T MOVE
    else
        return 1;
}

I don't know if this code is the best but it works... I want to convert this function to be a Memoized function. But I can't understand how & also why it would make the function more efficient. I understand why Fibonnaci in memoized is more efficient, but here I will always have to get to the end of the path and then return 1 or 0 so what does it matter if I store 1 / 0 inside an array for say?

Thanks for any kind of help


回答1:


It seems like you know what Memoization is. Basically, all you do is create a table memo which stores a value once you reach it so you don't have to calculate it in the recursion again. Something similar to why fibonacci(5) won't have to go into recursion to find fibonacci(3), if we have already calculated, say fibonacci(6), because we have memoized it. I hope you get it. Here is the code, memoized in the same spirit. Andrea's question has great visuals to understand.

long[][]memo;  //Memo table

public long C(int n)
{
    if (n == 1)
        return 0;

    memo=new int[n+1][n+1]; //Increase to n+1 and won't crash!

    for(int i=0;i<=n;i++)
        for(int j=0;j<=n;j++)
            memo[j][i]=-1;

    return C(n, 0, 0, memo);
}

private long C(int n, int i, int j, it) {

    // CAN MOVE UP & RIGHT
    if (j - i > 0 && j + 1 <= n)
    {
        if(memo[i+1][j]==-1)
            memo[i+1][j]=paths(n, i + 1, j);

        if(memo[i][j+1]==-1)
            memo[i][j+1]=paths(n, i, j + 1);

        return memo[i+1][j]+memo[i][j+1];
    }
    // CAN MOVE UP
    else if (j - i > 0)
    {
        if(memo[i+1][j]==-1)
            memo[i+1][j]=paths(n, i + 1, j);
        return memo[i+1][j];
    }
    // CAN MOVE RIGHT
    else if (j + 1 <= n)
    {
        if(memo[i][j+1]==-1)
            memo[i][j+1]=paths(n, i, j + 1);
        return memo[i][j+1];
    }
    // CAN'T MOVE
    else
        return 1;
}



回答2:


But I can't understand [...] why it would make the function more efficient.

Looking at the image, numbering the pictures starting with 1, and (x,y) coordinates with (0,0) in lower left corner, you can see that pictures 2,3,4, 5,6,7,8,10, 12, are all going through the point at (3,1).

Paths from (3,1):

  • (3,1) → (4,1) ↑ (4,2) ↑ (4,3) ↑ (4,4)
    • Picture 2, 4, 5
  • (3,1) ↑ (3,2) → (4,2) ↑ (4,3) ↑ (4,4)
    • Picture 3, 6, 8
  • (3,1) ↑ (3,2) ↑ (3,3) → (4,3) ↑ (4,4)
    • Picture 7, 10, 12

As you can see, you're walking the same path multiple (3) times. If you could cache (memoize) the fact that there are 3 paths from (3,1) to the end, you're saving time.

Time savings will grow as the grid gets bigger.


So, what you do, is that first time you get to a point, you calculate the result using recursion, as you already do, then save the number for that point, and when getting to the point again, you just use the cached value:

public static long paths(int n) {
    if (n == 1)
        return 0;
    return paths(n, 0, 0, new long[n][n]);
}
private static long paths(int n, int y, int x, long[][] cache) {
    long result = cache[y][x];
    if (result == 0) {
        if (y < x && x < n) // CAN MOVE UP & RIGHT
            result = paths(n, y + 1, x, cache) + paths(n, y, x + 1, cache);
        else if (y < x) // CAN MOVE UP
            result = paths(n, y + 1, x, cache);
        else if (x < n) // CAN MOVE RIGHT
            result = paths(n, y, x + 1, cache);
        else // CAN'T MOVE
            result = 1;
        cache[y][x] = result;
    }
    return result;
}


来源:https://stackoverflow.com/questions/34244047/recursion-for-catalan-number-to-memoized

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!