diff --git a/python/1203-sort-items-by-groups-respecting-dependencies.py b/python/1203-sort-items-by-groups-respecting-dependencies.py new file mode 100644 index 000000000..7da80aed8 --- /dev/null +++ b/python/1203-sort-items-by-groups-respecting-dependencies.py @@ -0,0 +1,63 @@ +from collections import defaultdict, deque +from typing import List +class Solution: + # This function performs topological sort on a directed graph represented by successors and predecessors_count arrays. + def topologicalSort(self, successors: List[List[int]], predecessors_count: List[int], num_nodes: int) -> List[int]: + order = [] # To store the topologically sorted nodes + # Initialize a deque with all nodes that have no predecessors (i.e., in-degree of 0) + nodes_with_no_predecessors = deque(node for node in range(num_nodes) if not predecessors_count[node]) + + while nodes_with_no_predecessors: # Process nodes while there are nodes without predecessors + node = nodes_with_no_predecessors.popleft() # Get the node with no predecessors + order.append(node) # Add the node to the sorted order + for successor in successors[node]: # For each successor of the current node + predecessors_count[successor] -= 1 # Decrement the in-degree of the successor + if not predecessors_count[successor]: # If the successor now has no predecessors + nodes_with_no_predecessors.append(successor) # Add it to the queue for processing + + # If the number of nodes in the order is less than the total number of nodes, a cycle was detected + return order if len(order) == num_nodes else [] # Return the order if all nodes were sorted, else return empty list + + def sortItems(self, n: int, m: int, group: List[int], beforeItems: List[List[int]]) -> List[int]: + # Step 1: Assign unique group IDs to items that don't belong to any group + for item in range(n): + if group[item] == -1: # If the item doesn't belong to any group + group[item] = m # Assign a new group ID + m += 1 # Increment the group ID for the next item + + # Step 2: Initialize graphs for item dependencies and group dependencies + successors_group, successors_item = [[] for _ in range(m)], [[] for _ in range(n)] # Graphs for group and item dependencies + predecessors_count_group, predecessors_count_item = [0] * m, [0] * n # Count of incoming edges (predecessors) for each group and item + + # Step 3: Build the dependency graphs based on beforeItems + for item in range(n): + current_group = group[item] # Get the group of the current item + for before in beforeItems[item]: # Process each item that should come before the current item + before_group = group[before] # Get the group of the item that should come before + + if current_group == before_group: # If the two items belong to the same group + successors_item[before].append(item) # Add a dependency from 'before' to the current item + predecessors_count_item[item] += 1 # Increment the in-degree of the current item + else: # If the items belong to different groups + successors_group[before_group].append(current_group) # Add a group dependency + predecessors_count_group[current_group] += 1 # Increment the in-degree of the current group + + # Step 4: Perform topological sort on both the group dependencies and item dependencies + groups_order = self.topologicalSort(successors_group, predecessors_count_group, m) # Topological sort of groups + items_order = self.topologicalSort(successors_item, predecessors_count_item, n) # Topological sort of items + + # Step 5: If there was a cycle detected in either group or item sorting, return an empty list + if not groups_order or not items_order: + return [] # Return an empty list if either the group or item topological sort failed + + # Step 6: Group the items based on the group IDs + items_grouped = [[] for _ in range(m)] # Create an empty list for each group to store its items + for item in items_order: # Process each item in topologically sorted order + items_grouped[group[item]].append(item) # Add the item to the appropriate group + + # Step 7: Combine the groups in topologically sorted order + result = [] # The final result list to store the sorted items + for grp in groups_order: # For each group in topologically sorted order + result.extend(items_grouped[grp]) # Add the items of the group to the result + + return result # Return the final sorted list of items respecting both item and group dependencies