Rotting Oranges

Problem

A grid has cells 0 (empty), 1 (fresh orange) and 2 (rotten orange). Every minute each fresh orange that is next to a rotten orange (up, down, left or right) becomes rotten. Print the number of minutes until no fresh orange is left, or -1 if some fresh orange can never rot. If there is no fresh orange at the start, print 0.

Constraints

  • 1 <= r, c <= 500

Examples

Input

3 3
2 1 1
1 1 0
0 1 1

Output

4

Solutions

Best approachTime O(r * c)Space O(r * c)

Starting the BFS from all rotten oranges together makes the time equal to the BFS level. A normal BFS from each orange separately would be much slower and give wrong times.

Same code works in Java810172125Basic features only, so nothing changes between versions.
/*
 * Problem : Rotting oranges.
 * Input   : r and c, then the grid.
 * Output  : The minutes or -1.
 * Approach: Multi-source BFS.
 * Time    : O(r * c)
 * Space   : O(r * c)
 * Java    : 8 or newer.
 */
import java.util.Scanner;

public class Main {
    // This method solves the task. It receives the input and returns the answer.
    static int solve(int[][] m) {
        int rows = m.length;
        int cols = m[0].length;

        // Step 1: Put all rotten oranges in the queue at the start (multi-source BFS). Count the fresh oranges.
        java.util.ArrayDeque<int[]> queue = new java.util.ArrayDeque<>();
        int fresh = 0;
        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < cols; j++) {
                if (m[i][j] == 2) {
                    queue.add(new int[] {i, j, 0});
                } else if (m[i][j] == 1) {
                    fresh++;
                }
            }
        }

        // Step 2: BFS in rounds. Each queue item remembers the minute when it rotted.
        int[][] moves = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
        int minutes = 0;
        while (!queue.isEmpty()) {
            int[] current = queue.poll();
            minutes = Math.max(minutes, current[2]);
            for (int[] move : moves) {
                int x = current[0] + move[0];
                int y = current[1] + move[1];

                // Step 3: A fresh neighbour rots one minute later. We mark it as rotten at once, so it is added only once.
                if (x >= 0 && x < rows && y >= 0 && y < cols && m[x][y] == 1) {
                    m[x][y] = 2;
                    fresh--;
                    queue.add(new int[] {x, y, current[2] + 1});
                }
            }
        }

        // Step 4: If a fresh orange is still left, it was never reached.
        return fresh == 0 ? minutes : -1;
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int rows = scanner.nextInt();
        int cols = scanner.nextInt();
        int[][] m = new int[rows][cols];
        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < cols; j++) {
                m[i][j] = scanner.nextInt();
            }
        }
        System.out.println(solve(m));
    }
}
Hints (1)
  1. Why start from all rotten oranges at once?