From c9bdd35f02789c5e8b2272193ec188b5dd63c57e Mon Sep 17 00:00:00 2001 From: Manasvi Reddy Date: Mon, 6 Jul 2026 01:05:33 -0400 Subject: [PATCH] Done BFS-2-1 --- Problem1.py | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++++ Problem2.py | 48 ++++++++++++++++++++++++++++++++++++ 2 files changed, 119 insertions(+) create mode 100644 Problem1.py create mode 100644 Problem2.py diff --git a/Problem1.py b/Problem1.py new file mode 100644 index 0000000..41714dc --- /dev/null +++ b/Problem1.py @@ -0,0 +1,71 @@ +# Problem 1: Rotting Oranges(https://leetcode.com/problems/rotting-oranges) +# Time Complexity: O(m*n) +# Space Complexity: O(m*n) +# Approach: +# First we scan the whole grid once to collect all rotten oranges into a queue and count how many fresh oranges exist. +# Then we do BFS minute by minute. In each minute we only process the oranges that were rotten at the start of that minute and rot their fresh neighbors, adding them to the queue for the next minute. +# If the fresh count reaches zero we return the current time right away. If the queue empties out before that happens, some oranges were unreachable, so we return minus one. + +class Solution: + def orangesRotting(self, grid: List[List[int]]) -> int: + + # these are the four possible moves from any cell, up down right left, used to check all four neighbors without writing four separate conditions + self.directions = [[-1,0],[1,0],[0,1],[0,-1]] + + + self.m = len(grid) # m is the number of rows in the grid + self.n = len(grid[0]) # n is the number of columns in the grid + + queue = [] # queue will hold the positions of rotten oranges that still need to spread their rot + fresh = 0 # fresh keeps a running count of how many fresh oranges are still left in the grid + + # this loop goes through every single cell in the grid exactly once + for i in range(self.m): + for j in range(self.n): + # if this cell is rotten, we add its position to the queue since it will spread rot from here + if grid[i][j] == 2: + queue.append((i, j)) + # if this cell is fresh, we simply increase our fresh counter + if grid[i][j] == 1: + fresh += 1 + + # time tracks how many minutes have passed + time = 0 + # if there were no fresh oranges to begin with, no rotting needs to happen, so we return zero right away + if fresh == 0: + return time + + # this loop keeps running as long as there are rotten oranges waiting to spread their rot + while queue: + # size captures exactly how many rotten oranges are in the queue at the start of this minute + # this is important because it tells us where one minute ends and the next minute begins + size = len(queue) + # one full minute is about to pass for all these oranges together, so we increase time now + time += 1 + + # we only loop size times so we only process oranges that belong to this exact minute, not oranges added during this same minute + for i in range(size): + # we take the orange that has been waiting the longest, since we want first in first out order + current = queue.pop(0) + + # we check all four neighbors of this rotten orange one by one + for dir in self.directions: + # row is the neighbor's row, found by adding the row change to the current row + row = current[0] + dir[0] + # column is the neighbor's column, found by adding the column change to the current column + column = current[1] + dir[1] + + # we only continue if the neighbor is inside the grid boundaries and the neighbor is currently a fresh orange + if row >= 0 and column >= 0 and row < self.m and column < self.n and grid[row][column] == 1: + # we mark this neighbor as rotten directly on the grid so it is never processed again + grid[row][column] = 2 + # we add this newly rotten orange to the queue so it can spread rot in the next minute + queue.append((row, column)) + # one less fresh orange remains now + fresh -= 1 + # if there are no fresh oranges left at all, we are done, so we return the current time immediately + if fresh == 0: + return time + + # if we reach here, the queue became empty but some fresh oranges never got rotten, meaning they were unreachable + return -1 diff --git a/Problem2.py b/Problem2.py new file mode 100644 index 0000000..2903e3c --- /dev/null +++ b/Problem2.py @@ -0,0 +1,48 @@ +# Problem 2: Employee Impotance(https://leetcode.com/problems/employee-importance/) +#Time Complexity: O(N), where N is the number of employees, because we visit each employee exactly once during the map building step and exactly once during the DFS step. +#Space Complexity: O(N), because we store every employee in the map and in the worst case the recursion stack can go as deep as N if the hierarchy is a long chain. +#Approach: We first build a map that connects each employee id to their actual employee object, since the subordinates list only gives us ids and not the full object. Then we use DFS starting from the given id, adding up the importance value of every employee we visit, including the starting employee and all their direct and indirect subordinates. The recursion naturally keeps going deeper until there are no more subordinates left to explore. + + +# Definition for Employee. +class Employee: + def __init__(self, id: int, importance: int, subordinates: List[int]): + self.id = id + self.importance = importance + self.subordinates = subordinates + + +class Solution: + def getImportance(self, employees: List['Employee'], id: int) -> int: + # this map will let us jump from an employee id straight to the actual employee object + # we need this because subordinates are stored as plain ids, not as objects we can use directly + self.map = {} + + # we loop through every employee once and store them in the map using their id as the key + # this way later on we can look up any employee in constant time instead of searching the whole list again + for emp in employees: + self.map[emp.id] = emp + + # this will hold the running total of importance as we visit employees + self.result = 0 + + # we start the depth first search from the given id + # this call will handle adding importance for this employee and all their subordinates + self.dfs(id) + return self.result + + def dfs(self, id): + # we look up the actual employee object for this id using our map + # this is fast because the map gives us direct access instead of searching + emp = self.map[id] + + # we add this employee's own importance value to the running total + # this happens for the starting employee and every subordinate we visit along the way + self.result += emp.importance + + # now we go through each subordinate id that belongs to this employee + for subid in emp.subordinates: + # we call dfs again on this subordinate + # this is what lets us reach not just direct subordinates but also their subordinates and so on + # the recursion keeps going deeper until it reaches an employee with no subordinates left + self.dfs(subid)