diff --git a/04- April/28- Similar String Groups/28- Similar String Groups (Mahmoud Aboelsoud).cpp b/04- April/28- Similar String Groups/28- Similar String Groups (Mahmoud Aboelsoud).cpp new file mode 100644 index 000000000..21682ccc0 --- /dev/null +++ b/04- April/28- Similar String Groups/28- Similar String Groups (Mahmoud Aboelsoud).cpp @@ -0,0 +1,79 @@ +// Author: Mahmoud Aboelsoud + +class Solution { +public: + // Disjoint Set Union (DSU) data structure + + vector parent, set_size; + + int find_set(int v){ + if(v == parent[v]) return v; + + return parent[v] = find_set(parent[v]); + } + + void union_sets(int a, int b){ + a = find_set(a); + b = find_set(b); + if(a != b){ + if(set_size[a] < set_size[b]) + swap(a, b); + parent[b] = a; + set_size[a] += set_size[b]; + } + } + + bool same_set(int a, int b){ + a = find_set(a); + b = find_set(b); + + return a == b; + } + + // in this problem we need to know how many similar groups are there + // we can do that by brute force and check each pair of strings if they are similar or not + // and if they are similar we can merge them in the same group which will help us to know the number of groups at the end + + + int numSimilarGroups(vector& strs) { + // n: number of strings + int n = strs.size(); + // parent: parent of each string + parent.assign(n, 0); + // set_size: size of each set + set_size.assign(n, 1); + + // initially each string is in its own set (group) and its parent is itself + for(int i = 0; i < n; i++) + parent[i] = i; + + + // we can check each pair of strings if they are similar or not and merge them in the same group if they are similar + for(int i = 0; i < n; i++){ + for(int j = i + 1; j < n; j++){ + // if they are not in the same group then we check if they are similar or not + if(!same_set(i, j)){ + // cnt: number of different characters between the two strings + int cnt = 0; + // loop over the two strings and count the number of different characters and add a condition to break the loop if the number of different characters is more than 2 + // because if the number of different characters is more than 2 then the two strings are not similar and we don't need to check the rest of the characters + for(int k = 0; k < strs[i].size() && cnt <= 2; k++) + cnt += (strs[i][k] != strs[j][k]); + + // if the number of different characters is 0 or 2 then the two strings are similar and we merge them in the same group + if(cnt == 0 || cnt == 2) union_sets(i, j); + } + } + } + + // st: set of parents of all strings + set st; + + // loop over all strings and insert their parents in the set + for(int i = 0; i < n ; i++) + st.insert(find_set(i)); + + // return the size of the set which is the number of groups + return st.size(); + } +}; diff --git a/04- April/28- Similar String Groups/28- Similar String Groups (Osama Ayman).java b/04- April/28- Similar String Groups/28- Similar String Groups (Osama Ayman).java new file mode 100644 index 000000000..1c673abca --- /dev/null +++ b/04- April/28- Similar String Groups/28- Similar String Groups (Osama Ayman).java @@ -0,0 +1,57 @@ +// Author: Osama Ayman +// Time: O(n*n*m) +// Space: O(n*n) +class Solution { + public int numSimilarGroups(String[] strs) { + // adjacency map to represent the graph + Map> adj = new HashMap<>(); + int n = strs.length; + // adding edges if they are similar + for(int i=0; i new ArrayList<>()).add(j); + adj.computeIfAbsent(j, k -> new ArrayList<>()).add(i); + } + } + } + int connectedComponents = 0; + Set vis = new HashSet<>(); + for(int i=0; i> adj, Set vis){ + if(vis.contains(node) || !adj.containsKey(node)) return; + vis.add(node); + for(int neigh: adj.get(node)){ + dfs(neigh, adj, vis); + } + } + private boolean isSimilar(String s1, String s2){ + char c1='.',c2='.'; + + for(int i=0; i +struct DSU { + // The parent vector stores the parent of each node, and the Gsize vector + // stores the size of each disjoint set. + vector parent, Gsize; + + // Constructor initializes the parent and Gsize vectors for all nodes. + DSU(int MaxNodes) { + parent = Gsize = vector(MaxNodes + 5); + for (int i = Base; i <= MaxNodes; i++) + parent[i] = i, Gsize[i] = 1; + } + + // Recursive function to find the leader of the disjoint set that the node + // belongs to, and updates the parent of all visited nodes to the leader. + T find_leader(int node) { + return parent[node] = (parent[node] == node ? node : find_leader(parent[node])); + } + + // Returns true if the two nodes belong to the same disjoint set. + bool is_same_sets(int u, int v) { + return find_leader(u) == find_leader(v); + } + + // Merges the disjoint sets containing the two nodes u and v. + void union_sets(int u, int v) { + int leader_u = find_leader(u), leader_v = find_leader(v); + if (leader_u == leader_v) return; + if (Gsize[leader_u] < Gsize[leader_v]) swap(leader_u, leader_v); + Gsize[leader_u] += Gsize[leader_v], parent[leader_v] = leader_u; + } + + // Returns the size of the disjoint set that the node belongs to. + int get_size(int u) { + return Gsize[find_leader(u)]; + } +}; + +class Solution { +public: + int maxNumEdgesToRemove(int n, vector>& edges) { + // Variable to store the number of edges removed. + int removed_edges = 0; + // Create two disjoint-set union objects, one for Alice and one for Bob. + DSU alice(n), bob(n); + // Sort edges in decreasing order of type so that type 3 edges are + // processed last. + sort(edges.rbegin(), edges.rend()); + // Loop through each edge in the sorted list. + for (auto& edge : edges) { + int t = edge[0], u = edge[1], v = edge[2]; + // Process the edge based on its type. + if (t == 1) { + if (alice.is_same_sets(u, v)) removed_edges++; + else alice.union_sets(u, v); + } else if (t == 2) { + if (bob.is_same_sets(u, v)) removed_edges++; + else bob.union_sets(u, v); + } else { + if (alice.is_same_sets(u, v) && bob.is_same_sets(u, v)) removed_edges++; + else alice.union_sets(u, v), bob.union_sets(u, v); + } + } + // Check if all nodes belong to the same disjoint set for both Alice and + // Bob. If not, return -1 as it is impossible to remove enough edges to + // create a spanning tree for both players. + if (alice.get_size(1) != n || bob.get_size(1) != n) + return -1; + // Return the number of edges removed. + return removed_edges; + } +}; diff --git a/04- April/README.md b/04- April/README.md index 10fcc20f1..0e2635750 100644 --- a/04- April/README.md +++ b/04- April/README.md @@ -51,6 +51,7 @@ 1. **[Add Digits](#26--add-digits)** 1. **[Bulb Switcher](#27--bulb-switcher)** 1. **[Similar String Groups](#28--similar-string-groups)** +1. **[Remove Max Number of Edges to Keep Graph Fully Traversable](#30--remove-max-number-of-edges-to-keep-graph-fully-traversable)**


@@ -1631,4 +1632,97 @@ public: }; ``` + +
+

+ +## 30) [Remove Max Number of Edges to Keep Graph Fully Traversable](https://leetcode.com/problems/remove-max-number-of-edges-to-keep-graph-fully-traversable/) + +### Difficulty + +![](https://img.shields.io/badge/Hard-red?style=for-the-badge) + +### Related Topic + +`Union Find` `Graph` + +### Code + + +```cpp +// Define a generic disjoint-set union data structure with an optional base node +// parameter for 1-based indexing, and a template parameter for data type T. +template +struct DSU { + // The parent vector stores the parent of each node, and the Gsize vector + // stores the size of each disjoint set. + vector parent, Gsize; + + // Constructor initializes the parent and Gsize vectors for all nodes. + DSU(int MaxNodes) { + parent = Gsize = vector(MaxNodes + 5); + for (int i = Base; i <= MaxNodes; i++) + parent[i] = i, Gsize[i] = 1; + } + + // Recursive function to find the leader of the disjoint set that the node + // belongs to, and updates the parent of all visited nodes to the leader. + T find_leader(int node) { + return parent[node] = (parent[node] == node ? node : find_leader(parent[node])); + } + + // Returns true if the two nodes belong to the same disjoint set. + bool is_same_sets(int u, int v) { + return find_leader(u) == find_leader(v); + } + + // Merges the disjoint sets containing the two nodes u and v. + void union_sets(int u, int v) { + int leader_u = find_leader(u), leader_v = find_leader(v); + if (leader_u == leader_v) return; + if (Gsize[leader_u] < Gsize[leader_v]) swap(leader_u, leader_v); + Gsize[leader_u] += Gsize[leader_v], parent[leader_v] = leader_u; + } + + // Returns the size of the disjoint set that the node belongs to. + int get_size(int u) { + return Gsize[find_leader(u)]; + } +}; + +class Solution { +public: + int maxNumEdgesToRemove(int n, vector>& edges) { + // Variable to store the number of edges removed. + int removed_edges = 0; + // Create two disjoint-set union objects, one for Alice and one for Bob. + DSU alice(n), bob(n); + // Sort edges in decreasing order of type so that type 3 edges are + // processed last. + sort(edges.rbegin(), edges.rend()); + // Loop through each edge in the sorted list. + for (auto& edge : edges) { + int t = edge[0], u = edge[1], v = edge[2]; + // Process the edge based on its type. + if (t == 1) { + if (alice.is_same_sets(u, v)) removed_edges++; + else alice.union_sets(u, v); + } else if (t == 2) { + if (bob.is_same_sets(u, v)) removed_edges++; + else bob.union_sets(u, v); + } else { + if (alice.is_same_sets(u, v) && bob.is_same_sets(u, v)) removed_edges++; + else alice.union_sets(u, v), bob.union_sets(u, v); + } + } + // Check if all nodes belong to the same disjoint set for both Alice and + // Bob. If not, return -1 as it is impossible to remove enough edges to + // create a spanning tree for both players. + if (alice.get_size(1) != n || bob.get_size(1) != n) + return -1; + // Return the number of edges removed. + return removed_edges; + } +}; +``` \ No newline at end of file