Algorithm to efficiently determine the [n][n] element in a matrix

前端 未结 6 407
半阙折子戏
半阙折子戏 2020-12-30 07:07

This is a question regarding a piece of coursework so would rather you didn\'t fully answer the question but rather give tips to improve the run time complexity of my curren

6条回答
  •  小鲜肉
    小鲜肉 (楼主)
    2020-12-30 07:38

    To describe time complexity we usually use a big O notation. It is important to remember that it only describes the growth given the input. O(n) is linear time complexity, but it doesn't say how quickly (or slowly) the time grows when we increase input. For example:

    n=3 -> 30 seconds
    n=4 -> 40 seconds
    n=5 -> 50 seconds
    

    This is O(n), we can clearly see that every increase of n increases the time by 10 seconds.

    n=3 -> 60 seconds
    n=4 -> 80 seconds
    n=5 -> 100 seconds
    

    This is also O(n), even though for every n we need twice that much time, and the raise is 20 seconds for every increase of n, the time complexity grows linearly.

    So if you have O(n*n) time complexity and you will half the number of operations you perform, you will get O(0.5*n*n) which is equal to O(n*n) - i.e. your time complexity won't change.

    This is theory, in practice the number of operations sometimes makes a difference. Because you have a grid n by n, you need to fill n*n cells, so the best time complexity you can achieve is O(n*n), but there are a few optimizations you can do:

    • Cells on the edges of the grid could be filled in separate loops. Currently in majority of the cases you have two unnecessary conditions for i and j equal to 0.
    • You grid has a line of symmetry, you could utilize it to calculate only half of it and then copy the results onto the other half. For every i and j grid[i][j] = grid[j][i]

    On final note, the clarity and readability of the code is much more important than performance - if you can read and understand the code, you can change it, but if the code is so ugly that you cannot understand it, you cannot optimize it. That's why I would do only first optimization (it also increases readability), but wouldn't do the second one - it would make the code much more difficult to understand.

    As a rule of thumb, don't optimize the code, unless the performance is really causing problems. As William Wulf said:

    More computing sins are committed in the name of efficiency (without necessarily achieving it) than for any other single reason - including blind stupidity.

    EDIT:

    I think it may be possible to implement this function with O(1) complexity. Although it gives no benefits when you need to fill entire grid, with O(1) time complexity you can instantly get any value without having a grid at all.

    Grid

    A few observations:

    • denominator is equal to 3 ^ (i + j - 1)
    • if i = 2 or j = 2, numerator is one less than denominator

    EDIT 2:

    The numerator can be expressed with the following function:

    public static int n(int i, int j) {
        if (i == 1 || j == 1) {
            return 1;
        } else {
            return 3 * n(i - 1, j - 1) + n(i - 1, j) + n(i, j - 1);
        }
    }
    

    Very similar to original problem, but no division and all numbers are integers.

提交回复
热议问题