Bird
Raised Fist0
Interview Prepunion-findhardAmazonGoogleFacebook

Remove Max Edges to Keep Graph Traversable

Choose your preparation mode4 modes available
📋
Problem

Imagine two friends, Alice and Bob, want to travel across a country using roads. Some roads are exclusive to Alice, some to Bob, and some shared. They want to remove as many roads as possible but still ensure both can travel anywhere in the country.

You are given an undirected graph with n nodes labeled from 1 to n. The graph has three types of edges: type 1 edges can be traversed by Alice only, type 2 edges by Bob only, and type 3 edges by both Alice and Bob. Your task is to remove the maximum number of edges such that after removal, both Alice and Bob can still traverse the entire graph (i.e., the graph is fully connected for both). Return the maximum number of edges you can remove, or -1 if it's impossible for both to traverse the entire graph.

1 ≤ n ≤ 10^51 ≤ edges.length ≤ min(10^5, n * (n - 1) / 2)edges[i].length == 31 ≤ edges[i][0] ≤ 31 ≤ edges[i][1] < edges[i][2] ≤ n
Edge cases: Graph with no edges → output -1 because no connectivityGraph with only type 3 edges → maximum removals possible while keeping connectivityGraph with edges only for Alice or only for Bob → likely -1
</>
IDE
def max_num_edges_to_remove(n: int, edges: list[list[int]]) -> int:public int maxNumEdgesToRemove(int n, int[][] edges)int maxNumEdgesToRemove(int n, vector<vector<int>>& edges)function maxNumEdgesToRemove(n, edges)
def max_num_edges_to_remove(n, edges):
    # Write your solution here
    pass
class Solution {
    public int maxNumEdgesToRemove(int n, int[][] edges) {
        // Write your solution here
        return 0;
    }
}
#include <vector>
using namespace std;

int maxNumEdgesToRemove(int n, vector<vector<int>>& edges) {
    // Write your solution here
    return 0;
}
function maxNumEdgesToRemove(n, edges) {
    // Write your solution here
}
Coming soon
0/9
Common Bugs to Avoid
Wrong: -1 when answer is non-negativeFailing to check connectivity for both Alice and Bob after edge removals.✅ After processing all edges, verify both Alice and Bob's union-find sets are fully connected before returning removable count.
Wrong: Incorrect removable count due to processing edges in wrong orderNot processing type 3 edges first, leading to suboptimal connectivity.✅ Process all type 3 edges first to maximize shared connectivity before processing type 1 and 2 edges.
Wrong: Removing edges that disconnect the graphRemoving edges without checking if they connect already connected components.✅ Only remove edges that connect nodes already in the same union-find set.
Wrong: Failing to remove duplicate edgesNot skipping union operations for edges connecting already connected nodes.✅ Skip union-find merges for edges connecting nodes in the same set and count them as removable.
Wrong: TLE on large inputsUsing brute force or inefficient union-find without path compression.✅ Implement union-find with path compression and union by rank to achieve near O(m α(n)) time.
✓
Test Cases
t1_01basic
Input{"n":4,"edges":[[3,1,2],[3,2,3],[1,1,3],[1,2,4],[1,1,2],[2,3,4]]}
Expected2

We can remove two edges while keeping the graph fully traversable for both Alice and Bob.

t1_02basic
Input{"n":4,"edges":[[3,1,2],[1,1,3],[2,2,4],[3,1,4],[2,1,4],[1,2,3]]}
Expected1

One edge can be removed while keeping both Alice and Bob fully connected.

t2_01edge
Input{"n":4,"edges":[]}
Expected-1

No edges means no connectivity for Alice or Bob, so return -1.

t2_02edge
Input{"n":3,"edges":[[3,1,2],[3,2,3],[3,1,3]]}
Expected0

All edges are type 3 and all needed to keep full connectivity; no edges can be removed.

t2_03edge
Input{"n":3,"edges":[[1,1,2],[1,2,3]]}
Expected-1

Edges only for Alice; Bob cannot traverse the graph, so return -1.

t3_01corner
Input{"n":4,"edges":[[1,1,2],[2,2,3],[1,3,4],[2,1,4]]}
Expected-1

No type 3 edges and edges do not connect both Alice and Bob fully; graph disconnected for both.

t3_02corner
Input{"n":5,"edges":[[3,1,2],[3,2,3],[1,1,4],[2,4,5],[1,3,5]]}
Expected0

Edges connect all nodes but no removable edges; greedy must not remove any edge that breaks connectivity.

t3_03corner
Input{"n":4,"edges":[[3,1,2],[3,2,3],[3,3,4],[1,1,3],[2,2,4],[1,1,4],[2,1,4]]}
Expected3

Multiple duplicate edges exist; duplicates can be removed safely.

t4_01performance
Input{"n":100,"edges":[[3,1,2],[3,2,3],[3,3,4],[3,4,5],[3,5,6],[3,6,7],[3,7,8],[3,8,9],[3,9,10],[3,10,11],[1,11,12],[1,12,13],[1,13,14],[1,14,15],[1,15,16],[1,16,17],[1,17,18],[1,18,19],[1,19,20],[1,20,21],[2,21,22],[2,22,23],[2,23,24],[2,24,25],[2,25,26],[2,26,27],[2,27,28],[2,28,29],[2,29,30],[2,30,31],[3,31,32],[3,32,33],[3,33,34],[3,34,35],[3,35,36],[3,36,37],[3,37,38],[3,38,39],[3,39,40],[3,40,41],[1,41,42],[1,42,43],[1,43,44],[1,44,45],[1,45,46],[1,46,47],[1,47,48],[1,48,49],[1,49,50],[1,50,51],[2,51,52],[2,52,53],[2,53,54],[2,54,55],[2,55,56],[2,56,57],[2,57,58],[2,58,59],[2,59,60],[2,60,61],[3,61,62],[3,62,63],[3,63,64],[3,64,65],[3,65,66],[3,66,67],[3,67,68],[3,68,69],[3,69,70],[3,70,71],[1,71,72],[1,72,73],[1,73,74],[1,74,75],[1,75,76],[1,76,77],[1,77,78],[1,78,79],[1,79,80],[1,80,81],[2,81,82],[2,82,83],[2,83,84],[2,84,85],[2,85,86],[2,86,87],[2,87,88],[2,88,89],[2,89,90],[2,90,91],[3,91,92],[3,92,93],[3,93,94],[3,94,95],[3,95,96],[3,96,97],[3,97,98],[3,98,99],[3,99,100]]}
⏱ Performance - must finish in 2000ms

n=100, edges=100, O(m α(n)) union-find complexity must complete within 2 seconds.

Practice

(1/5)
1. Consider the following Python code implementing Kruskal's MST with union by size and path compression. Given the input graph with edges [(0,1,1), (1,2,2), (0,2,3)] and n=3, what is the value of mst_weight after processing all edges?
easy
A. 3
B. 4
C. 5
D. 6

Solution

  1. Step 1: Sort edges by weight

    Edges sorted: (0,1,1), (1,2,2), (0,2,3)
  2. Step 2: Process edges and union sets

    Union(0,1) succeeds, mst_weight=1; Union(1,2) succeeds, mst_weight=3; Union(0,2) fails (already connected).
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Sum of edges in MST is 1+2=3 [OK]
Hint: Sum weights of first n-1 edges that connect components [OK]
Common Mistakes:
  • Adding all edges regardless of cycle
  • Off-by-one in edges_used count
  • Misordering edges before union
2. You are given a set of stones placed on a 2D grid. A move consists of removing a stone that shares either the same row or the same column with another stone. Which algorithmic approach guarantees finding the maximum number of stones that can be removed?
easy
A. Greedy approach removing stones one by one without tracking connectivity
B. Union-Find data structure connecting stones by rows and columns to find connected components
C. Dynamic programming to count stones based on row and column indices
D. Sorting stones by coordinates and removing duplicates

Solution

  1. Step 1: Understand problem connectivity

    Stones can be removed if they share a row or column, which forms connected components of stones.
  2. Step 2: Recognize union-find suitability

    Union-Find efficiently groups stones by connecting those sharing rows or columns, enabling counting of connected components.
  3. Final Answer:

    Option B -> Option B
  4. Quick Check:

    Union-Find finds connected components in near-linear time [OK]
Hint: Connectivity by rows/columns -> union-find [OK]
Common Mistakes:
  • Assuming greedy removal always works
  • Trying DP without connectivity insight
  • Sorting stones doesn't solve connectivity
3. Examine the following buggy DFS code for counting provinces. Which line contains the subtle bug that can cause incorrect results or infinite recursion?
medium
A. Line 4: visited[city] = True
B. Line 2: for neighbor in graph[city]:
C. Line 1: def dfs(city: int):
D. Line 3: if not visited[neighbor]:

Solution

  1. Step 1: Understand DFS visit marking

    Visited nodes must be marked before recursive calls to avoid revisiting and infinite loops.
  2. Step 2: Identify bug in visit marking

    Marking visited after recursion causes repeated visits and possible infinite recursion.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Visited marking must be before recursion to prevent cycles [OK]
Hint: Visited marking after recursion causes infinite loops [OK]
Common Mistakes:
  • Marking visited too late
  • Confusing visited marking with neighbor iteration
4. Suppose the Accounts Merge problem is extended so that emails can be reused across multiple users (e.g., shared family emails). Which modification to the union-find approach correctly handles this scenario?
hard
A. Use a graph with edges between accounts and emails, then find connected components allowing multiple parents
B. Keep union-find as is; emails connected once belong to a single user
C. Modify union-find to allow multiple parents per node to represent shared emails
D. Assign emails to users greedily by first occurrence, ignoring overlaps

Solution

  1. Step 1: Understand the new constraint

    Emails can belong to multiple users, so union-find's single parent per node model breaks down.
  2. Step 2: Choose correct data structure

    A bipartite graph connecting accounts and emails with connected components allows shared emails without forcing merges.
  3. Step 3: Evaluate other options

    Union-find cannot represent multiple parents; greedy assignment loses correctness.
  4. Final Answer:

    Option A -> Option A
  5. Quick Check:

    Graph approach models shared emails correctly [OK]
Hint: Union-find assumes disjoint sets; shared emails break this [OK]
Common Mistakes:
  • Trying to modify union-find for multiple parents
  • Ignoring shared emails and merging incorrectly
5. Suppose the problem is modified so that each connection can be used multiple times (i.e., cables are reusable), and you want to find the minimum number of operations to connect all computers. Which modification to the algorithm is correct?
hard
A. Check if the number of connections is at least n-1; if yes, return components - 1, else return -1.
B. Use a BFS or DFS to find the minimum spanning tree since reuse allows cycles.
C. Count connected components and return zero if at least one connection exists, since reuse removes cable limits.
D. No change needed; the original union-find solution still applies directly.

Solution

  1. Step 1: Understand reuse impact

    Reusing cables means the only constraint is having enough cables to connect all nodes, i.e., at least n-1 connections.
  2. Step 2: Apply union-find with check

    We still count connected components and need at least n-1 cables; if so, minimum operations = components - 1; else -1.
  3. Step 3: Reject naive assumptions

    No change needed; the original union-find solution still applies directly. ignores cable count; Use a BFS or DFS to find the minimum spanning tree since reuse allows cycles. is unnecessary; Count connected components and return zero if at least one connection exists, since reuse removes cable limits. incorrectly assumes any connection suffices.
  4. Final Answer:

    Option A -> Option A
  5. Quick Check:

    Minimum cables needed remains n-1 even with reuse [OK]
Hint: Cable reuse doesn't remove minimum cable count requirement [OK]
Common Mistakes:
  • Assuming reuse means zero operations
  • Ignoring minimum cable count
  • Switching to BFS unnecessarily
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard