简体   繁体   中英

Generalize hourglass movement in 2D Array - DS in Python

While working through this HackerRank challenge to prepare for interviews, stumbled across a blocker.

Basically want to create a function hourglassSum that should return an integer (the maximum hourglass sum in the array). Given a 6 x 6 2D Array, arr:

1 1 1 0 0 0
0 1 0 0 0 0
1 1 1 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0

There are 16 hourglasses in arr, and an hourglass sum is the sum of an hourglass' values. In that case, the sum of an hourglass' is 7.

This is the code I currently have (it's commented so it should be easy to understand the decisions being made too)

def hourglassSum(arr):
    #print(f"arr: {arr}")
    #print(f"arr[1]: {arr[1]}")
    #print(f"arr[1][1]: {arr[1][1]}")
    num_rows = len(arr)
    num_cols = len(arr[0])
    hg_total = 0
    hg_current_sum = 0 
    hg_max_sum = 0
    i = 0
    j = 0
    
    # There's no hourglass
    if 0 <= num_rows <= 3 or 0 <= num_cols <= 3:
        hg_total = 0
        hg_max_sum = 0
        
    # There's hourglass
    else:
        if num_rows > num_cols:
            # hg_total = num_cols - 2 + ( num_rows - num_cols ) 
            hg_total = num_rows - 2
        #elif num_cols > num_rows:
        else:
            # hg_total = num_rows - 2 + ( num_cols - num_rows ) 
            hg_total = num_cols - 2
        # irrelevant and could be added to any of the others, transforming the elif into else
        # else:
        #    hg_total = num_rows - 2
    
    # only one hourglass        
    if hg_total == 1:
        # calculate hg_current_sum
        row_1 = arr[0][0:3]
        row_2 = arr[1][1]
        row_3 = arr[2][0:3]
        
        #input
        """
        1 1 1 0 0 0
        0 1 0 0 0 0
        1 1 1 0 0 0
        0 0 2 4 4 0
        0 0 0 2 0 0
        0 0 1 2 4 0
        """
        #print(f"row_1: {row_1}")
        #print(f"row_2: {row_2}")
        #print(f"row_3: {row_3}")
        #output
        """
        row_1: [1, 1, 1]
        row_2: 1
        row_3: [1, 1, 1]
        """
            
        # Note that row_2 won't have sum() because it'll be always int and not a list of numbers
        hg_current_sum = sum(row_1) + row_2 + sum(row_3)
        hg_max_sum = hg_current_sum
        return hg_max_sum
            
    # Generalize
    while i < num_rows:
        row_1 = arr[i][0:3]
        row_2 = arr[i+1][1]
        row_3 = arr[i+2][0:3]
                
        hg_current_sum = sum(row_1) + row_2 + sum(row_3)
                
        # 9 is the highest value for a cell
        # 7 is the amount of cells in each hourglass
        # lowest_sum = -9 * 7
        # Hightest_sum = 9 * 7
        if hg_current_sum == 9*7:
            hg_max_sum = hg_current_sum
            break
        elif hg_current_sum > hg_max_sum:
            hg_max_sum = hg_current_sum
                    
        i = i + 2
        
    while j < num_cols:
        row_1 = arr[0][j:j+2]
        row_2 = arr[1][j+1]
        row_3 = arr[2][j:j+2]
                
        hg_current_sum = sum(row_1) + row_2 + sum(row_3)
                
        # 9 is the highest value for a cell
        # 7 is the amount of cells in each hourglass
        # lowest_sum = -9 * 7
        # Hightest_sum = 9 * 7
        if hg_current_sum == 9*7:
            hg_max_sum = hg_current_sum
            break
        elif hg_current_sum > hg_max_sum:
            hg_max_sum = hg_current_sum
                    
        j = j + 2
         
    return hg_max_sum

If I execute this, it will give a

Error (stderr) Traceback (most recent call last): File

"Solution.py", line 119, in

result = hourglassSum(arr) File "Solution.py", line 74, in hourglassSum

row_3 = arr[i+2][0:3] IndexError: list index out of range


The problem I'm having is in the generalization of the behaviour, from the comment # Generalize onwards. That moment onwards, starts the scenario of more than one hourglasses.

I can see how the movement of the hourglass should happen: top left -> top right (moving 1 cell to the right until the furthest right cell in the hourglass reaches the last existing column in the array) and repeat this process moving 1 cell down until the furthest down cell in the hourglass reaches the last row / bottom of the array.

Can see it could be done with a for loop (going from left -> right) inside of a for loop (going from top -> bottom). So, something like

for i in range(num_rows)
    # do stuff
    for j in range(num_cells)
        # do stuff    

This would ofc make the part within loops nearly unnecessary; the only reason I have them here is to visualize the movement of each cell to the right or to the bottom.

What then?

Moving to the right, I would update each part of the hourglass as a "sliding window," subtracting the former leftmost element and adding the new rightmost element. Start a new hourglass when moving the hourglass down a row.

Here's JavaScript code, easily convertable to Python:

 function f(m){ if (m.length < 3 || m[0].length < 3) return null; let row1, row2, row3; let best = -Infinity; for (let i=0; i<m.length-2; i++){ // Update the hourglass moving down row1 = m[i][0] + m[i][1] + m[i][2]; row2 = m[i+1][1]; row3 = m[i+2][0] + m[i+2][1] + m[i+2][2]; best = Math.max(best, row1 + row2 + row3); for (let j=1; j<m[0].length-2; j++){ // Update the hourglass moving to the right row1 += m[i][j+2] - m[i][j-1]; row2 = m[i+1][j+1]; row3 += m[i+2][j+2] - m[i+2][j-1]; best = Math.max(best, row1 + row2 + row3); } } return best; } var m = [ [1, 1, 1, 0, 0, 0], [0, 1, 0, 0, 0, 0], [1, 1, 1, 0, 0, 0], [0, 0, 2, 4, 4, 0], [0, 0, 0, 2, 0, 0], [0, 0, 1, 2, 4, 0] ]; console.log(f(m));

Update by Tiago Martins Peres 李大仁:

and here's the Python code:

def hourglassSum(arr):
    #print(f"arr: {arr}")
    #print(f"arr[1]: {arr[1]}")
    #print(f"arr[1][1]: {arr[1][1]}")
    num_rows = len(arr)
    num_cols = len(arr[0])
    hg_max_sum = -float('Inf') #-inf
    hg_current_sum = 0
    i = 0
    j = 1
    
    # There's no hourglass
    if 0 <= num_rows <= 3 or 0 <= num_cols <= 3:
        hg_max_sum = 0
    
    for i in range(0,num_rows - 2):
        # Update the hourglass moving down
        row1 = arr[i][0] + arr[i][1] + arr[i][2];
        row2 = arr[i+1][1];
        row3 = arr[i+2][0] + arr[i+2][1] + arr[i+2][2];
        hg_current_sum = row1 + row2 + row3
        #print(f"1_ hg_current_sum: {hg_current_sum}")
    
        hg_max_sum = max(hg_max_sum, hg_current_sum);
        
        #print(f"1_ hg_max_sum: {hg_max_sum}")
        
        for j in range(1,num_cols - 2):
            # Update the hourglass moving to the right
            row1 += arr[i][j+2] - arr[i][j-1];
            row2 = arr[i+1][j+1];
            row3 += arr[i+2][j+2] - arr[i+2][j-1];
            hg_current_sum = row1 + row2 + row3
            #print(f"2_ hg_current_sum: {hg_current_sum}")
        
            hg_max_sum = max(hg_max_sum, hg_current_sum);
            #print(f"2_ hg_max_sum: {hg_max_sum}")
        
    return hg_max_sum

basically the difference is that now

  • Removed some of the complexity you were adding by focusing in the essential
  • Made hg_max_sum as -inf
  • Used the for inside of the for where one moves down in the initial column (hence i = 0) and the other moves to the right and down (hence j = 1)
  • Removed ++i and ++j because the loop will increment it necessarily based on the given range
  • Got right away the sum in each row_1, row_2 and row_3 (no need to store their real values) and associates it to a variable hg_current_sum
  • Uses the max() function to compare the highest value so far (hg_max_sum) with hg_current_sum

This will pass all the current tests

最后结果

  public static int hourglassSum(List<List<int>> arr)
    { 
       int[] sum = new int[16];
        int hourglass = 0;
        for (int i = 0; i < 4; i++)
        {
            for (int j = 0; j < 4; j++)
            {
                sum[hourglass] = 
                          arr[i][j] + arr[i][j + 1] + arr[i][j + 2]
                        + arr[i + 1][j + 1] 
                        + arr[i + 2][j] + arr[i + 2][j + 1] + arr[i + 2][j + 2];
                hourglass++;
            }
        }
          return sum.Max();;
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM