Skip to content

BFS-2.1 completed#617

Open
sujaygijre wants to merge 2 commits into
super30admin:mainfrom
sujaygijre:main
Open

BFS-2.1 completed#617
sujaygijre wants to merge 2 commits into
super30admin:mainfrom
sujaygijre:main

Conversation

@sujaygijre
Copy link
Copy Markdown

No description provided.

@super30admin
Copy link
Copy Markdown
Owner

Strengths:

  • You used BFS, which is the appropriate algorithm for this problem.
  • You attempted to handle edge cases, such as when there are no fresh oranges.
  • The code is structured with helper lambdas, which can improve readability.

Areas for Improvement:

  1. Unnecessary Data Structures: Using sets and string keys for coordinates is inefficient. Instead, you can directly use the grid to check the state of oranges and maintain a simple integer count of fresh oranges.
  2. Time Calculation: The time variable is initialized to -1 and then incremented at each level. This might lead to off-by-one errors. In the reference solution, time starts at 0 and is incremented after processing each level. Also, the initial rotten oranges are processed at time 0, so the first expansion should be at time 1.
  3. Edge Case Handling: Your condition for returning 0 is not entirely correct. For example, if there are no rotten oranges but there are fresh oranges, your solution would return -1 (which is correct) but if there are no fresh oranges and no rotten oranges, it should return 0. However, your code checks if both sets are empty, which might not cover all cases.
  4. Efficiency: The string operations (key generation) and set lookups are expensive. It's better to avoid them and use the grid directly.
  5. Code Simplicity: The solution can be simplified by following the reference approach: count fresh oranges, use a queue for BFS, and decrement the fresh count when an orange becomes rotten.

Suggested Changes:

  • Remove the sets us and freshO.
  • Instead, maintain a counter fresh for the number of fresh oranges.
  • Use the grid to mark rotten oranges (by setting to 2) and check for fresh oranges (value 1).
  • Initialize time to 0 and only increment after processing each level of BFS. However, note that the initial rotten oranges are at minute 0, so the first expansion should be at minute 1.
  • After BFS, if fresh is 0, return time, else return -1.

Example correction (based on reference solution):

class Solution {
public:
    int orangesRotting(vector<vector<int>>& grid) {
        int m = grid.size(), n = grid[0].size();
        int fresh = 0;
        queue<pair<int, int>> q;
        vector<vector<int>> dirs = {{1,0}, {-1,0}, {0,1}, {0,-1}};
        
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (grid[i][j] == 1) fresh++;
                else if (grid[i][j] == 2) q.push({i, j});
            }
        }
        
        if (fresh == 0) return 0;
        
        int time = 0;
        while (!q.empty()) {
            int size = q.size();
            time++;
            for (int i = 0; i < size; i++) {
                auto [x, y] = q.front(); q.pop();
                for (auto& dir : dirs) {
                    int nx = x + dir[0], ny = y + dir[1];
                    if (nx >= 0 && ny >= 0 && nx < m && ny < n && grid[nx][ny] == 1) {
                        grid[nx][ny] = 2;
                        fresh--;
                        q.push({nx, ny});
                        if (fresh == 0) return time;
                    }
                }
            }
        }
        
        return -1;
    }
};

@super30admin
Copy link
Copy Markdown
Owner

Strengths:

  • You have attempted to use BFS, which is the standard approach for this problem.
  • You considered the directions using a direction vector.
  • You tried to handle edge cases.

Areas for improvement:

  1. Focus on one problem at a time. The solution includes code for a different problem (EmployeeImportance.cpp), which should not be mixed with the current problem.
  2. Avoid using sets for tracking visited and fresh oranges when the grid itself can be used. This simplifies the code and reduces memory.
  3. Initialize time to 0 and then increment after processing each level of BFS. However, note that the first level (initial rotten oranges) should not contribute to time because they are already rotten at time 0.
  4. Instead of sets, maintain a count of fresh oranges. Decrement this count whenever a fresh orange becomes rotten. If the count becomes zero, return the current time. If after BFS there are still fresh oranges, return -1.
  5. The initial condition should check if there are any fresh oranges. If not, return 0 immediately.
  6. The BFS should start with all rotten oranges in the queue. Then, for each minute, process all oranges in the queue (current level) and then increment time.
  7. Remove the lambda functions and use direct grid checks for simplicity and performance.

Here is a corrected version of your code without the sets:

class Solution {
public:
    vector<vector<int>> dirs = {{1,0}, {-1,0}, {0,1}, {0,-1}};
    int orangesRotting(vector<vector<int>>& grid) {
        queue<pair<int, int>> q;
        int fresh = 0;
        int m = grid.size(), n = grid[0].size();
        
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (grid[i][j] == 2) {
                    q.push({i, j});
                } else if (grid[i][j] == 1) {
                    fresh++;
                }
            }
        }
        
        if (fresh == 0) return 0;
        
        int time = 0;
        while (!q.empty()) {
            int size = q.size();
            for (int i = 0; i < size; i++) {
                auto [x, y] = q.front(); q.pop();
                for (auto& dir : dirs) {
                    int nx = x + dir[0], ny = y + dir[1];
                    if (nx >= 0 && ny >= 0 && nx < m && ny < n && grid[nx][ny] == 1) {
                        grid[nx][ny] = 2;
                        q.push({nx, ny});
                        fresh--;
                    }
                }
            }
            time++;
            if (fresh == 0) return time;
        }
        
        return -1;
    }
};

Note: The above code increments time after processing each level. However, the first level (initial rotten oranges) is processed without incrementing time? Actually, we start with time=0, and after processing the first level we increment time to 1. But the initial rotten oranges are at time 0. So when we process the initial queue, we are going to infect neighbors at time 1. This is correct.

But in the code above, we return time when fresh becomes zero after processing a level. So for the first infection, we return time=1.

However, in the reference solution, time is initialized to 0 and then incremented at the beginning of the while loop. Then it returns time when fresh becomes zero. This is equivalent.

But in your original code, you started time at -1 and then incremented at the beginning of the while loop. Then after processing all, you returned time. This would be off by one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants