Problem

Farmer John has a rectangular grass pasture with N rows and M columns for the cows to graze on. Each pasture has a certain tastiness value. However, the gen alpha Bessie has gotten quite picky with what she eats.

Given a 2D array (template below) with size NxM, please write functions for the following:

  1. getTotalGrass()
    • Return total sum of all “tastiness values” from the pastures in the 2D array
  2. maxSquare()
    • Because Bessie sometimes likes enjoying square grass patches, she wants to find the best one.
    • Returns the maximum sum of tastiness value of a square in the 2D array. (Square could be 1x1, 2x2, 3x3, etc.)
  3. maxSubarraySum()
    • Sometimes, Bessie enjoys eating grass in a line.
    • Return the maximum sum of a continuous subarray in this array if it was “flattened” to be a 1D array. In other words, make the 2D array into a 1D array by combining all rows and find the max subarray sum.

For an example case, see below in the code.

Extra Credit Opportunities

Extra Credit 1 (+0.01): What is the time complexity of your maxSquare code? Explain.

Extra Credit 2 (+0.01): This is achieved if you get the optimal complexity for maxPatch.

Extra Credit 3 (+0.01): What is the time complexity of your maxSubarraySum code? Explain.

Extra Credit 4 (+0.01): This is achieved if you get the optimal complexity for maxSubarraySum.

public class GrassPasture {
    /** The 2D grid of pasture tastiness values */
    private int[][] pastures;

    /** Constructor initializes the field */
    public GrassPasture(int[][] pastures) {
        this.pastures = pastures;
    }

    /**
     * Returns sum of total tastiness for all values in 2D array
     */
    public int getTotalGrass() {
        int total = 0;
        for (int[] row : pastures) {
            for (int value : row) {
                total += value;
            }
        }
        return total;
    }

    /**
     * Returns max sum of tastiness of a square in the 2D array (square can be 1x1, 2x2, etc.)
     */
    public int maxSquare() {
        int n = pastures.length;
        int m = pastures[0].length;
        int maxSum = Integer.MIN_VALUE;

        for (int size = 1; size <= Math.min(n, m); size++) {
            for (int i = 0; i <= n - size; i++) {
                for (int j = 0; j <= m - size; j++) {
                    int sum = 0;
                    for (int x = 0; x < size; x++) {
                        for (int y = 0; y < size; y++) {
                            sum += pastures[i + x][j + y];
                        }
                    }
                    maxSum = Math.max(maxSum, sum);
                }
            }
        }
        return maxSum;
    }

    /**
     * Returns the maximum tastiness sum subarray in the flattened 2D grid
     */
    public int maxSubarraySum() {
        int n = pastures.length;
        int m = pastures[0].length;
        int maxSum = Integer.MIN_VALUE;

        for (int left = 0; left < m; left++) {
            int[] temp = new int[n];
            for (int right = left; right < m; right++) {
                for (int i = 0; i < n; i++) {
                    temp[i] += pastures[i][right];
                }
                maxSum = Math.max(maxSum, kadane(temp));
            }
        }
        return maxSum;
    }

    /**
     * Kadane's algorithm to find the max subarray sum in a 1D array
     */
    private int kadane(int[] arr) {
        int maxEndingHere = arr[0], maxSoFar = arr[0];
        for (int i = 1; i < arr.length; i++) {
            maxEndingHere = Math.max(arr[i], maxEndingHere + arr[i]);
            maxSoFar = Math.max(maxSoFar, maxEndingHere);
        }
        return maxSoFar;
    }

    public static void main(String[] args) {
        int[][] pastures = {
            {-3, 6, -1},
            {2, -1, 5},
            {-9, 4, -1}
        };

        GrassPasture gp = new GrassPasture(pastures);

        System.out.println("Total Tastiness: " + gp.getTotalGrass()); // should be -2
        System.out.println("Max Square Sum: " + gp.maxSquare()); // should be 9
        System.out.println("Max Subarray Sum: " + gp.maxSubarraySum()); // should be 11
    }
}