0

I am working on the rotten oranges problem:

In a given grid, each cell can have one of three values:

  • the value 0 representing an empty cell;
  • the value 1 representing a fresh orange;
  • the value 2 representing a rotten orange.

Every minute, any fresh orange that is adjacent (4-directionally) to a rotten orange becomes rotten.

Return the minimum number of minutes that must elapse until no cell has a fresh orange. If this is impossible, return -1 instead.

Example 1:

  • Input: [[1,1,1],[1,1,0],[0,1,2]]
  • Output: 4

I've implemented a BFS solution. Then after finishing the BFS, I initiate another iteration to make sure that there's no fresh orange left, because if there are fresh oranges left over, then I have to return -1.

However, I find that in that final loop only some of the values were changed into 2, and some others remain at 1. I'm not sure why they are not changed to 2 as well.

class Solution {
    public int orangesRotting(int[][] grid) {
        //need adjacency list/matrix
        Queue<String> q = new LinkedList<>();
        int[] count = new int[1];
        count[0] = 0;
        for(int i = 0; i < grid.length; i++) {
            for(int j = 0; j < grid[i].length; j++) {
                if(grid[i][j] == 2) {
                    q.add("" + i + j);
                    bfs(grid, i, j, count, q);
                }
            }
        }
        
        for(int i = 0; i < grid.length; i++) {
            for(int j = 0; j < grid[i].length; j++) {
                // does NOT always print correct value: 1 is not changed to 2
                System.out.println(grid[i][j]); 
                if(grid[i][j] == 1) {
                    return -1;  // ... and so this -1 is returned when it shouldn't
                }
            }
        }
        
        return count[0];
    }
    
    private static void bfs(int[][] grid, int i, int j, int[] count,  Queue<String> q) {
        while(!q.isEmpty()) {
            String s = q.remove();
            //System.out.println(s); //prints correct indices
            i = Integer.parseInt(s.substring(0,1));
            j = Integer.parseInt(s.substring(1));
            
            if(i - 1 > 0 && grid[i - 1][j] == 1) {
                count[0]++;
                i--;
                grid[i][j] = 2;
                q.add("" + i + j);
            }
            if(i + 1 < grid.length && grid[i + 1][j] == 1) {
                count[0]++;
                i++;
                grid[i][j] = 2;
                q.add("" + i + j);
            }
            if(j - 1 > 0 && grid[i][j - 1] == 1) {
                count[0]++;
                j--;
                grid[i][j] = 2;
                q.add("" + i + j);
            }
            if(j + 1 < grid.length && grid[i][j + 1] == 1) {
                count[0]++;
                j++;
                grid[i][j] = 2;
                q.add("" + i + j);
            }
        }
        
    }
    
}

My code outputs -1 for the above quoted example, because it still finds a 1 in the final loop, while it shouldn't.

Could you help me figure out why this is happening?

trincot
  • 317,000
  • 35
  • 244
  • 286
j.Doie
  • 91
  • 1
  • 6
  • **else if**? After entering one _if_ one could enter a second _if_. One could introduce a `nextI`. – Joop Eggen Sep 25 '20 at 22:15
  • @JoopEggen that's meant to happen because an orange could be next you 4 others that are not rotten and in one bfs iteration they should all be added to the queue – j.Doie Sep 25 '20 at 22:40
  • Could you explain _what_ exactly "the rotten oranges problem" is? – tobias_k Sep 26 '20 at 07:57

1 Answers1

0

Several issues:

  • The cells in column 0 or row 0 are never checked for infecting oranges. The comparison i - 1 > 0 is not true when i is 1, yet you should also check grid[0][j]... The same issue occurs with j.

  • By modifying i with i--, you impact the next if conditions, which are intended to look at the original value of i. So you should not change the value of i (nor of j), but assign to grid[i-1][j] without modification of i.

  • In bfs, the j index is wrongly compared to grid.length. It should be compared against grid[i].length as the grid is not guaranteed to be square.

  • The count is increased for every orange that is made rotten, but that is not what should be counted. Many oranges can turn rotten in the same minute, and you should only count minutes, not oranges. To count correctly you should make two changes:

    • Only make the initial call to bfs when you have collected all rotten oranges in the queue, since they all belong to minute 0.

    • In the bfs function itself, add new rotten oranges to a separate queue, so you know which ones were added in this particular minute. Then when the original queue becomes empty, move the second queue to the first, account for a next minute, and repeat.

  • Not a problem, but there is no need to pass i and j as arguments to bfs, and instead of passing a reference to a counter, let bfs return the count.

I have tried to not change more than necessary in your code to make it work:

class Solution {
    public int orangesRotting(int[][] grid) {
        Queue<String> q = new LinkedList<>();
        for(int i = 0; i < grid.length; i++) {
            for(int j = 0; j < grid[i].length; j++) {
                if(grid[i][j] == 2) {
                    q.add("" + i + j);
                }
            }
        }
        // Only call BFS when all rotten oranges on "minute 0" are identified
        int count = bfs(grid, q);       
        for(int i = 0; i < grid.length; i++) {
            for(int j = 0; j < grid[i].length; j++) {
                System.out.println(grid[i][j]); //does NOT print correct value, not changed to 2
                if(grid[i][j] == 1) {
                   return -1;
                }
            }
        }      
        return count;
    }
    
    private static int bfs(int[][] grid, Queue<String> q) {
        int count = 0;
        while(true) { // One iteration per minute
            // Use another queue for the next minute
            Queue<String> q2 = new LinkedList<>();
            // Populate the new queue with oranges that get rotten in this minute
            while(!q.isEmpty()) {
                String s = q.remove();
                int i = Integer.parseInt(s.substring(0,1));
                int j = Integer.parseInt(s.substring(1));
                if(i - 1 >= 0 && grid[i - 1][j] == 1) {
                    // Do not increase the counter for each separate orange!
                    // ...and do not change the value of i or j.
                    grid[i-1][j] = 2;
                    q2.add("" + (i-1) + j);
                }
                if(i + 1 < grid.length && grid[i + 1][j] == 1) {
                    grid[i+1][j] = 2;
                    q2.add("" + (i+1) + j);
                }
                if(j - 1 >= 0 && grid[i][j - 1] == 1) {
                    grid[i][j-1] = 2;
                    q2.add("" + i + (j-1));
                }
                // Compare against the correct length
                if(j + 1 < grid[i].length && grid[i][j + 1] == 1) {
                    grid[i][j+1] = 2;
                    q2.add("" + i + (j+1));
                }
            }
            if (q2.isEmpty()) { // No new oranges were turned rotten
                return count;
            }
            // Continue for a next minute: only now increase the counter
            count++;
            q = q2;
        }
    } 
}

There are surely ways to make this run more efficiently, like using arrays instead of queues.

trincot
  • 317,000
  • 35
  • 244
  • 286