diff --git a/EmployeeImportance.swift b/EmployeeImportance.swift new file mode 100644 index 0000000..e7a8f7a --- /dev/null +++ b/EmployeeImportance.swift @@ -0,0 +1,126 @@ +// +// EmployeeImportance.swift +// DSA-Practice +// +// Created by Paridhi Malviya on 1/31/26. +// + + +class EmployeeImportance { + + private class QueueUsingLL { + + class LinkedListNode { + var value: T + var next: LinkedListNode? + init(value: T) { + self.value = value + } + } + + private var front: LinkedListNode? + private var rear: LinkedListNode? + private var count: Int = 0 + + func enqueue(_ val: T) { + let newNode = LinkedListNode(value: val) + if (front == nil) { + front = newNode + rear = newNode + } else { + rear?.next = newNode + rear = newNode + } + count += 1 + } + + func dequeue() -> T? { + if (front == nil) { + return nil + } + + let value = front?.value + front = front?.next + if (front == nil) { + rear = nil + } + count -= 1 + return value + } + + var isEmpty: Bool { + return count == 0 + } + + var size: Int { + return count + } + } + + class Employee { + let id: Int + let importance: Int + let subordinates: [Int] + + init(id: Int, importance: Int, subordinates: [Int]) { + self.id = id + self.importance = importance + self.subordinates = subordinates + } + } + + //MARK: BFS + /* + time complexity -> Number of employees O(V) + Actually O(V + E) -> E - no of edges. 1 employee is reporting to 1 manager only. So, E = V, O(2V) = O(V) + */ + func getImportance(_ employees: [Employee], _ id: Int) -> Int { + var hashMap = Dictionary() + for employee in employees { + hashMap[employee.id] = employee + } + + //BFS + let queue = QueueUsingLL() + queue.enqueue(id) + + var totalImportance = 0 + while (!queue.isEmpty) { + guard let empId = queue.dequeue() else { + continue + } + if let employee = hashMap[empId] { + totalImportance += employee.importance + for subordinate in employee.subordinates { + queue.enqueue(subordinate) + } + } + } + return totalImportance + } + + //MARK: Using DFS + func getImportanceUsingDFS(_ employees: [Employee], _ id: Int) -> Int { + + var hashMap = Dictionary() + for emp in employees { + hashMap[emp.id] = emp + } + + let totalImportance = dfs(id: id, hashMap: hashMap) + return totalImportance + + } + + func dfs(id: Int, hashMap: Dictionary) -> Int { + guard let emp = hashMap[id] else { + return 0 + } + + var totalImportance = emp.importance + for subordinate in emp.subordinates { + totalImportance += dfs(id: subordinate, hashMap: hashMap) + } + return totalImportance + } +} diff --git a/RottenOranges.swift b/RottenOranges.swift new file mode 100644 index 0000000..1d700e7 --- /dev/null +++ b/RottenOranges.swift @@ -0,0 +1,190 @@ +// +// RottenOranges.swift +// DSA-Practice +// +// Created by Paridhi Malviya on 1/21/26. +// + +class RottenOranges { + + class QueueUsingLinkedList { + + private class LinkedListNode { + var value: T + var next: LinkedListNode? + init(value: T) { + self.value = value + } + } + + private var front: LinkedListNode? + private var rear: LinkedListNode? + private var count: Int = 0 + + func enqueue(_ val: T) { + let newNode = LinkedListNode(value: val) + if (front == nil) { + front = newNode + rear = newNode + } else { + rear?.next = newNode + rear = newNode + } + count += 1 + } + + func dequeue() -> T? { + if (front == nil) { + return nil + } + let frontValue = front?.value + front = front?.next + if (front == nil) { + rear = nil + } + count -= 1 + return frontValue + } + + var isEmpty: Bool { + return count == 0 + } + + var size: Int { + return count + } + } + + + + /* + In how much tume, oranges will be rotten. + If all oranges can't be rotten, then return -1. + + time compelxity - O(m * n) + space complexity - O(m * n) worst case- when all oranges are rotten + If only 1 ornge is rotten in the wntore matrix - N/4 , N = m * n, in queue we will hav1 ,1 -> 4 -> 16 -> 64 .... 1/4 doesn't matter, SO O(N) = O(m * n) + + */ + init() { +// let output = orangesRotting([[2,1,1],[1,1,0],[0,1,1]]) + let o = rottenOrangesUsingDFS([[2,1,1],[1,1,0],[0,1,1]]) + print("o \(o)") + } + + func orangesRotting(_ grid: [[Int]]) -> Int { + var grid = grid + let m = grid.count + let n = grid[0].count + var fresh = 0 + + let directionsArray = [[0,1], [0, -1], [1, 0], [-1, 0]] + var queue = QueueUsingLinkedList<(Int,Int)>() + for i in 0..= 0 && newC >= 0 && newR < m && newC < n && grid[newR][newC] == 1) { + //change the state and enqueue + grid[newR][newC] = 2 + queue.enqueue((newR, newC)) + fresh -= 1 + if (fresh == 0) { + return time + 1 + } + } + } + } + time += 1 + } + //if any fresh orange is left then return -1 + if (fresh == 0) { + return time - 1 + } + return -1 + } + + /* + DFS from the same node will cause the trouble. These kinds of issue can be present in many DFS problems. + If connected component is there, with DFS, we can't achieve the solution. + Trick - We can visit the node which are already visited if we are getting better time from some other path. + It will handle infinite loop issue as well. It will optimize the time as well. + Don't start time from 1 to avoid confusion between 1 (fresh) and 2 (rotten ) oranges. Start it from 3. + Space complexity -> O(m * n) -> because in dfs, the recursion stack can have max of m*n elements when traversing + time complexity - amortized m*n. From first node, we are doing full traversin to update the time. For the 2nd DFS, it wouldn't traverse the whole matrix, it will check mostly the immediate neighbours. It doesn't go until the full lenth of matrix. With each node, we will be having lesser and lesser node to optimize. Hence time complexty becomes amortized m*n + */ + + func rottenOrangesUsingDFS(_ grid: [[Int]]) -> Int { + var grid = grid + + let m = grid.count + let n = grid[0].count + + //traverse through each node and initiate dfs. Visit the node again and again to optimize time + for i in 0..