2508. Add Edges to Make Degrees of All Nodes Even
Problem Description
You are given an undirected graph with n
nodes numbered from 1
to n
. The graph is defined by a 2D array edges
where edges[i] = [ai, bi]
represents an edge between nodes ai
and bi
. The graph may be disconnected.
Your task is to determine if you can add at most two additional edges (possibly none) to make every node in the graph have an even degree. The degree of a node is the number of edges connected to it.
Rules for adding edges:
- No repeated edges allowed (no duplicate edges)
- No self-loops allowed (a node cannot connect to itself)
Return true
if it's possible to make all nodes have even degrees by adding at most 2 edges, otherwise return false
.
Example 1: Given n = 5
and edges connecting nodes as shown, you can add one edge to make all nodes have even degrees, so return true
.
Example 2: Given n = 4
with edges [[1,2],[3,4]]
, you can add two edges (like connecting 1-3 and 2-4) to make all nodes have even degrees, so return true
.
Example 3: Given n = 4
with edges [[1,2],[1,3],[1,4]]
, node 1 has degree 3 (odd) and nodes 2, 3, 4 each have degree 1 (odd). It's impossible to make all nodes have even degrees by adding at most 2 edges, so return false
.
The key insight is that adding an edge between two nodes increases the degree of both nodes by 1. Since you can add at most 2 edges, you can increase degrees for at most 4 nodes. This means if there are more than 4 nodes with odd degrees, it's impossible to fix them all.
Intuition
The key observation is that adding an edge between two nodes increases both their degrees by 1. Since we want all nodes to have even degrees, we need to identify which nodes currently have odd degrees and figure out how to make them even.
Let's think about what happens when we add edges:
- Adding 1 edge affects exactly 2 nodes (increases each by 1)
- Adding 2 edges affects at most 4 nodes
This immediately tells us that if we have more than 4 nodes with odd degrees, it's impossible to fix them all with at most 2 edges.
Now let's analyze the different cases:
Case 1: 0 nodes with odd degree
All nodes already have even degrees, so we don't need to add any edges. Return true
.
Case 2: 2 nodes with odd degree
We have nodes a
and b
with odd degrees. If we add an edge between them, both become even. But what if they're already connected? Then we need to find a "helper" node c
that isn't connected to either a
or b
. We can add edges a-c
and b-c
, which makes all three nodes change parity (oddβeven for a
and b
, and c
stays even if it was even or becomes even if it was odd).
Case 3: 4 nodes with odd degree
We have nodes a
, b
, c
, d
with odd degrees. We need to pair them up somehow using 2 edges. There are three possible pairings:
- Connect
a-b
andc-d
- Connect
a-c
andb-d
- Connect
a-d
andb-c
We check if any of these pairings is valid (i.e., the edges don't already exist).
Case 4: Any other number of odd-degree nodes For 1 or 3 nodes with odd degree, it's impossible because each edge changes exactly 2 nodes' parity. For more than 4 nodes with odd degree, we can't fix all of them with just 2 edges.
The solution naturally follows from counting odd-degree nodes and handling each case appropriately.
Learn more about Graph patterns.
Solution Approach
The implementation follows our case analysis strategy:
Step 1: Build the graph representation
We use a defaultdict(set)
to store the adjacency list. For each edge [a, b]
, we add b
to g[a]
and a
to g[b]
. Using sets helps us quickly check if an edge exists between two nodes.
g = defaultdict(set)
for a, b in edges:
g[a].add(b)
g[b].add(a)
Step 2: Find all nodes with odd degrees We iterate through the graph and collect nodes whose degree (size of their adjacency set) is odd:
vs = [i for i, v in g.items() if len(v) & 1]
The expression len(v) & 1
checks if the degree is odd (bitwise AND with 1).
Step 3: Handle different cases based on the count of odd-degree nodes
Case 0 nodes: All nodes have even degrees already.
if len(vs) == 0:
return True
Case 2 nodes: Try to connect them directly, or find a common third node.
if len(vs) == 2:
a, b = vs
if a not in g[b]: # Can directly connect a and b
return True
# Try to find a node c that can connect to both a and b
return any(a not in g[c] and c not in g[b] for c in range(1, n + 1))
Case 4 nodes: Try all three possible pairings.
if len(vs) == 4:
a, b, c, d = vs
if a not in g[b] and c not in g[d]: # Pair (a,b) and (c,d)
return True
if a not in g[c] and b not in g[d]: # Pair (a,c) and (b,d)
return True
if a not in g[d] and b not in g[c]: # Pair (a,d) and (b,c)
return True
return False
Any other case: Return false
as it's impossible to make all degrees even with at most 2 edges.
return False
The time complexity is O(E + N)
where E
is the number of edges (for building the graph) and N
is the number of nodes (for checking potential connections in the worst case). The space complexity is O(E)
for storing the graph.
Ready to land your dream job?
Unlock your dream job with a 5-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through a concrete example to illustrate the solution approach.
Example: n = 6
, edges = [[1,2], [2,3], [3,4], [4,5]]
Step 1: Build the graph
Node 1: connected to {2} β degree = 1 (odd) Node 2: connected to {1, 3} β degree = 2 (even) Node 3: connected to {2, 4} β degree = 2 (even) Node 4: connected to {3, 5} β degree = 2 (even) Node 5: connected to {4} β degree = 1 (odd) Node 6: connected to {} β degree = 0 (even)
Step 2: Find odd-degree nodes
Nodes with odd degrees: [1, 5]
Count = 2
Step 3: Apply Case 2 logic Since we have exactly 2 nodes with odd degrees, we check:
- Can we directly connect nodes 1 and 5?
- Check if edge (1,5) already exists: No, it doesn't exist
- We can add edge (1,5)!
After adding edge (1,5):
- Node 1: degree becomes 2 (even) β
- Node 5: degree becomes 2 (even) β
- All other nodes remain even β
Result: Return true
- we made all degrees even by adding just 1 edge.
Another Example: n = 4
, edges = [[1,2], [2,3], [3,1]]
(a triangle)
Step 1: Build the graph
Node 1: connected to {2, 3} β degree = 2 (even) Node 2: connected to {1, 3} β degree = 2 (even) Node 3: connected to {1, 2} β degree = 2 (even) Node 4: connected to {} β degree = 0 (even)
Step 2: Find odd-degree nodes
Nodes with odd degrees: []
Count = 0
Step 3: Apply Case 0 logic All nodes already have even degrees!
Result: Return true
- no edges need to be added.
Impossible Example: n = 4
, edges = [[1,2], [1,3], [1,4]]
(star graph)
Step 1: Build the graph
Node 1: connected to {2, 3, 4} β degree = 3 (odd) Node 2: connected to {1} β degree = 1 (odd) Node 3: connected to {1} β degree = 1 (odd) Node 4: connected to {1} β degree = 1 (odd)
Step 2: Find odd-degree nodes
Nodes with odd degrees: [1, 2, 3, 4]
Count = 4
Step 3: Apply Case 4 logic We need to try all possible pairings:
- Pair (1,2) and (3,4):
- Edge (1,2) already exists β
- Cannot use this pairing
- Pair (1,3) and (2,4):
- Edge (1,3) already exists β
- Cannot use this pairing
- Pair (1,4) and (2,3):
- Edge (1,4) already exists β
- Cannot use this pairing
All possible pairings fail because node 1 is already connected to all other nodes.
Result: Return false
- impossible to make all degrees even with at most 2 edges.
Solution Implementation
1class Solution:
2 def isPossible(self, n: int, edges: List[List[int]]) -> bool:
3 # Build adjacency list representation of the graph
4 adjacency_list = defaultdict(set)
5 for node_a, node_b in edges:
6 adjacency_list[node_a].add(node_b)
7 adjacency_list[node_b].add(node_a)
8
9 # Find all vertices with odd degree
10 odd_degree_vertices = [vertex for vertex, neighbors in adjacency_list.items()
11 if len(neighbors) % 2 == 1]
12
13 # If all vertices have even degree, graph is already Eulerian
14 if len(odd_degree_vertices) == 0:
15 return True
16
17 # If exactly 2 vertices have odd degree
18 if len(odd_degree_vertices) == 2:
19 vertex_a, vertex_b = odd_degree_vertices
20
21 # Check if we can directly connect these two vertices
22 if vertex_a not in adjacency_list[vertex_b]:
23 return True
24
25 # Try to find an intermediate vertex to connect both odd-degree vertices
26 for intermediate_vertex in range(1, n + 1):
27 if (vertex_a not in adjacency_list[intermediate_vertex] and
28 intermediate_vertex not in adjacency_list[vertex_b]):
29 return True
30 return False
31
32 # If exactly 4 vertices have odd degree
33 if len(odd_degree_vertices) == 4:
34 vertex_a, vertex_b, vertex_c, vertex_d = odd_degree_vertices
35
36 # Try all three possible pairings to connect the 4 vertices
37 # Pairing 1: (a,b) and (c,d)
38 if (vertex_a not in adjacency_list[vertex_b] and
39 vertex_c not in adjacency_list[vertex_d]):
40 return True
41
42 # Pairing 2: (a,c) and (b,d)
43 if (vertex_a not in adjacency_list[vertex_c] and
44 vertex_b not in adjacency_list[vertex_d]):
45 return True
46
47 # Pairing 3: (a,d) and (b,c)
48 if (vertex_a not in adjacency_list[vertex_d] and
49 vertex_b not in adjacency_list[vertex_c]):
50 return True
51
52 return False
53
54 # More than 4 vertices with odd degree cannot be fixed with at most 2 edges
55 return False
56
1class Solution {
2 public boolean isPossible(int n, List<List<Integer>> edges) {
3 // Create adjacency list representation of the graph
4 // Using Set to avoid duplicate edges and for O(1) lookup
5 Set<Integer>[] graph = new Set[n + 1];
6 Arrays.setAll(graph, index -> new HashSet<>());
7
8 // Build the undirected graph from edge list
9 for (List<Integer> edge : edges) {
10 int nodeA = edge.get(0);
11 int nodeB = edge.get(1);
12 graph[nodeA].add(nodeB);
13 graph[nodeB].add(nodeA);
14 }
15
16 // Find all vertices with odd degree
17 // For Eulerian path to exist, we need all vertices to have even degree
18 List<Integer> oddDegreeVertices = new ArrayList<>();
19 for (int vertex = 1; vertex <= n; ++vertex) {
20 if (graph[vertex].size() % 2 == 1) {
21 oddDegreeVertices.add(vertex);
22 }
23 }
24
25 // Case 1: No vertices with odd degree - already Eulerian
26 if (oddDegreeVertices.size() == 0) {
27 return true;
28 }
29
30 // Case 2: Exactly 2 vertices with odd degree
31 if (oddDegreeVertices.size() == 2) {
32 int vertexA = oddDegreeVertices.get(0);
33 int vertexB = oddDegreeVertices.get(1);
34
35 // Can directly connect the two odd-degree vertices
36 if (!graph[vertexA].contains(vertexB)) {
37 return true;
38 }
39
40 // Try to find an intermediate vertex to connect both odd-degree vertices
41 for (int intermediateVertex = 1; intermediateVertex <= n; ++intermediateVertex) {
42 if (intermediateVertex != vertexA &&
43 intermediateVertex != vertexB &&
44 !graph[vertexA].contains(intermediateVertex) &&
45 !graph[intermediateVertex].contains(vertexB)) {
46 return true;
47 }
48 }
49 return false;
50 }
51
52 // Case 3: Exactly 4 vertices with odd degree
53 if (oddDegreeVertices.size() == 4) {
54 int vertexA = oddDegreeVertices.get(0);
55 int vertexB = oddDegreeVertices.get(1);
56 int vertexC = oddDegreeVertices.get(2);
57 int vertexD = oddDegreeVertices.get(3);
58
59 // Try all possible pairings to make all degrees even
60 // Pairing 1: (A-B) and (C-D)
61 if (!graph[vertexA].contains(vertexB) && !graph[vertexC].contains(vertexD)) {
62 return true;
63 }
64 // Pairing 2: (A-C) and (B-D)
65 if (!graph[vertexA].contains(vertexC) && !graph[vertexB].contains(vertexD)) {
66 return true;
67 }
68 // Pairing 3: (A-D) and (B-C)
69 if (!graph[vertexA].contains(vertexD) && !graph[vertexB].contains(vertexC)) {
70 return true;
71 }
72 return false;
73 }
74
75 // More than 4 vertices with odd degree - impossible to fix with at most 2 edges
76 return false;
77 }
78}
79
1class Solution {
2public:
3 bool isPossible(int n, vector<vector<int>>& edges) {
4 // Build adjacency list using unordered_set for O(1) lookup
5 // Graph is 1-indexed (vertices from 1 to n)
6 vector<unordered_set<int>> adjacencyList(n + 1);
7
8 // Populate the adjacency list with undirected edges
9 for (auto& edge : edges) {
10 int vertex1 = edge[0];
11 int vertex2 = edge[1];
12 adjacencyList[vertex1].insert(vertex2);
13 adjacencyList[vertex2].insert(vertex1);
14 }
15
16 // Find all vertices with odd degree
17 vector<int> oddDegreeVertices;
18 for (int vertex = 1; vertex <= n; ++vertex) {
19 if (adjacencyList[vertex].size() % 2 == 1) {
20 oddDegreeVertices.emplace_back(vertex);
21 }
22 }
23
24 // If all vertices have even degree, graph is already valid
25 if (oddDegreeVertices.size() == 0) {
26 return true;
27 }
28
29 // Case 1: Exactly 2 vertices with odd degree
30 // We need to add 1 edge between them or through an intermediate vertex
31 if (oddDegreeVertices.size() == 2) {
32 int vertexA = oddDegreeVertices[0];
33 int vertexB = oddDegreeVertices[1];
34
35 // If edge doesn't exist between A and B, we can directly connect them
36 if (!adjacencyList[vertexA].count(vertexB)) {
37 return true;
38 }
39
40 // Edge exists between A and B, try to find intermediate vertex C
41 // We need edges A-C and C-B where both don't exist
42 for (int vertexC = 1; vertexC <= n; ++vertexC) {
43 if (vertexA != vertexC && vertexB != vertexC &&
44 !adjacencyList[vertexA].count(vertexC) &&
45 !adjacencyList[vertexC].count(vertexB)) {
46 return true;
47 }
48 }
49 return false;
50 }
51
52 // Case 2: Exactly 4 vertices with odd degree
53 // We need to add 2 edges to make all 4 vertices have even degree
54 if (oddDegreeVertices.size() == 4) {
55 int vertexA = oddDegreeVertices[0];
56 int vertexB = oddDegreeVertices[1];
57 int vertexC = oddDegreeVertices[2];
58 int vertexD = oddDegreeVertices[3];
59
60 // Try all possible pairings: (A-B, C-D), (A-C, B-D), (A-D, B-C)
61 // Pairing 1: Connect A with B and C with D
62 if (!adjacencyList[vertexA].count(vertexB) &&
63 !adjacencyList[vertexC].count(vertexD)) {
64 return true;
65 }
66
67 // Pairing 2: Connect A with C and B with D
68 if (!adjacencyList[vertexA].count(vertexC) &&
69 !adjacencyList[vertexB].count(vertexD)) {
70 return true;
71 }
72
73 // Pairing 3: Connect A with D and B with C
74 if (!adjacencyList[vertexA].count(vertexD) &&
75 !adjacencyList[vertexB].count(vertexC)) {
76 return true;
77 }
78
79 return false;
80 }
81
82 // For any other number of odd degree vertices (1, 3, or > 4)
83 // It's impossible to make all vertices even with at most 2 edges
84 return false;
85 }
86};
87
1function isPossible(n: number, edges: number[][]): boolean {
2 // Build adjacency list using Set for O(1) lookup
3 // Graph is 1-indexed (vertices from 1 to n)
4 const adjacencyList: Set<number>[] = Array(n + 1)
5 .fill(null)
6 .map(() => new Set<number>());
7
8 // Populate the adjacency list with undirected edges
9 for (const edge of edges) {
10 const vertex1 = edge[0];
11 const vertex2 = edge[1];
12 adjacencyList[vertex1].add(vertex2);
13 adjacencyList[vertex2].add(vertex1);
14 }
15
16 // Find all vertices with odd degree
17 const oddDegreeVertices: number[] = [];
18 for (let vertex = 1; vertex <= n; vertex++) {
19 if (adjacencyList[vertex].size % 2 === 1) {
20 oddDegreeVertices.push(vertex);
21 }
22 }
23
24 // If all vertices have even degree, graph is already valid
25 if (oddDegreeVertices.length === 0) {
26 return true;
27 }
28
29 // Case 1: Exactly 2 vertices with odd degree
30 // We need to add 1 edge between them or through an intermediate vertex
31 if (oddDegreeVertices.length === 2) {
32 const vertexA = oddDegreeVertices[0];
33 const vertexB = oddDegreeVertices[1];
34
35 // If edge doesn't exist between A and B, we can directly connect them
36 if (!adjacencyList[vertexA].has(vertexB)) {
37 return true;
38 }
39
40 // Edge exists between A and B, try to find intermediate vertex C
41 // We need edges A-C and C-B where both don't exist
42 for (let vertexC = 1; vertexC <= n; vertexC++) {
43 if (vertexA !== vertexC &&
44 vertexB !== vertexC &&
45 !adjacencyList[vertexA].has(vertexC) &&
46 !adjacencyList[vertexC].has(vertexB)) {
47 return true;
48 }
49 }
50 return false;
51 }
52
53 // Case 2: Exactly 4 vertices with odd degree
54 // We need to add 2 edges to make all 4 vertices have even degree
55 if (oddDegreeVertices.length === 4) {
56 const vertexA = oddDegreeVertices[0];
57 const vertexB = oddDegreeVertices[1];
58 const vertexC = oddDegreeVertices[2];
59 const vertexD = oddDegreeVertices[3];
60
61 // Try all possible pairings: (A-B, C-D), (A-C, B-D), (A-D, B-C)
62
63 // Pairing 1: Connect A with B and C with D
64 if (!adjacencyList[vertexA].has(vertexB) &&
65 !adjacencyList[vertexC].has(vertexD)) {
66 return true;
67 }
68
69 // Pairing 2: Connect A with C and B with D
70 if (!adjacencyList[vertexA].has(vertexC) &&
71 !adjacencyList[vertexB].has(vertexD)) {
72 return true;
73 }
74
75 // Pairing 3: Connect A with D and B with C
76 if (!adjacencyList[vertexA].has(vertexD) &&
77 !adjacencyList[vertexB].has(vertexC)) {
78 return true;
79 }
80
81 return false;
82 }
83
84 // For any other number of odd degree vertices (1, 3, or > 4)
85 // It's impossible to make all vertices even with at most 2 edges
86 return false;
87}
88
Time and Space Complexity
Time Complexity: O(n + m)
The algorithm consists of the following operations:
- Building the adjacency list by iterating through all edges:
O(m)
wherem
is the number of edges - Finding vertices with odd degree by iterating through the graph dictionary:
O(n)
wheren
is the number of nodes (at mostn
vertices in the graph) - When there are 2 vertices with odd degree, checking if they're connected takes
O(1)
, and theany()
function iterates through all nodes from 1 ton+1
, checking set membership operations which areO(1)
each, resulting inO(n)
- When there are 4 vertices with odd degree, we perform constant number of set membership checks:
O(1)
The dominant operations are building the graph O(m)
and the potential iteration through all nodes O(n)
, giving us a total time complexity of O(n + m)
.
Space Complexity: O(n + m)
The space usage includes:
- The adjacency list
g
which stores all edges as sets: each edge(a, b)
is stored twice (once for each direction), requiringO(m)
space for all edges - Each vertex can appear in the graph, requiring
O(n)
space for the dictionary keys - The list
vs
stores at most 4 vertices with odd degree:O(1)
The adjacency list dominates the space usage with O(n + m)
total space complexity.
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Incorrectly handling isolated nodes
A critical pitfall is not accounting for nodes that have no edges at all (isolated nodes). These nodes have degree 0 (even) and won't appear in the adjacency list if we only build it from the edges.
Problem Example:
n = 5, edges = [[1,2], [3,4]] # Node 5 is isolated with degree 0 # Our current code would miss node 5 entirely
In the case of 2 odd-degree nodes, when searching for an intermediate vertex, the code iterates from 1
to n+1
, but if a node doesn't exist in the adjacency list (like node 5), checking vertex_a not in adjacency_list[intermediate_vertex]
would always return True
since adjacency_list[5]
would be an empty set.
Solution: Ensure isolated nodes are properly handled by either:
- Pre-populating the adjacency list with all nodes
- Being careful when checking for non-existent edges
# Initialize all nodes in the graph first
adjacency_list = {i: set() for i in range(1, n + 1)}
for node_a, node_b in edges:
adjacency_list[node_a].add(node_b)
adjacency_list[node_b].add(node_a)
2. Self-loop confusion when checking intermediate vertices
When looking for an intermediate vertex in the 2-node case, there's a subtle issue if we're not careful about the condition check.
Problem Example:
# Current check: if (vertex_a not in adjacency_list[intermediate_vertex] and intermediate_vertex not in adjacency_list[vertex_b]):
This check has an asymmetry - it checks if vertex_a
is not in intermediate_vertex
's neighbors, but then checks if intermediate_vertex
is not in vertex_b
's neighbors. While this works due to the undirected nature of the graph, it's confusing and error-prone.
Solution: Use consistent checking pattern:
if (vertex_a not in adjacency_list[intermediate_vertex] and vertex_b not in adjacency_list[intermediate_vertex]):
3. Not considering the intermediate vertex could be one of the odd-degree vertices
When we have 2 odd-degree vertices and need to find an intermediate vertex, we might accidentally allow one of the odd-degree vertices to be the intermediate vertex, which would create a self-loop.
Problem Example:
If vertex_a = 1
and vertex_b = 2
, and we check intermediate_vertex = 1
, we'd be trying to add edges (1,1) and (1,2), where (1,1) is a self-loop.
Solution: Explicitly exclude the odd-degree vertices from being intermediate vertices:
for intermediate_vertex in range(1, n + 1):
if intermediate_vertex in {vertex_a, vertex_b}:
continue # Skip if it's one of the odd-degree vertices
if (vertex_a not in adjacency_list[intermediate_vertex] and
vertex_b not in adjacency_list[intermediate_vertex]):
return True
Which algorithm is best for finding the shortest distance between two points in an unweighted graph?
Recommended Readings
https assets algo monster cover_photos graph svg Graph Fundamentals Tree with 0 cycle At this point you should be pretty familiar with trees A tree is a special kind of graph a connected acyclic cycle less graph A graph may contain cycle s and nodes could be disconnected A tree
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https assets algo monster recursion jpg You first call Ben and ask
Want a Structured Path to Master System Design Too? Donβt Miss This!