Add Edges to Make Degrees of All Nodes Even solution and explanation
9 more videos on this problem
Weekly Contest 324 | Add Edges to Make Degrees of All Nodes EvencodingMohan · 16:28 · 919 views
Leetcode 2508. Add Edges to Make Degrees of All Nodes EvenThinkCode · 19:57 · 894 views
2508. Add Edges to Make Degrees of All Nodes Even | Weekly Contest 324 | LeetCode 2508Bro Coders · 10:24 · 877 views
2508 Add Edges to Make Degrees of All Nodes Even | Leetcode Weekly contest 324Programming Pathshala · 11:47 · 593 views
2508. Add Edges to Make Degrees of All Nodes Even (Leetcode Hard)Programming Live with Larry · 18:21 · 431 views
Leetcode Weekly contest 324 - Hard - Add Edges to Make Degrees of All Nodes EvenPrakhar Agrawal · 11:01 · 374 views
【每日一题】LeetCode 2508. Add Edges to Make Degrees of All Nodes EvenHuifeng Guan · 14:05 · 310 views
Add Edges to Make Degrees of All Nodes Even | 2508 LeetCode | Graphs | Leetcode Weekly Contest 324CodeWithSunny · 16:46 · 304 views
Leetcode 2508. Add Edges to Make Degrees of All Nodes EvenElite Code · 35:30 · 159 views
LC 2508.Add Edges to Make Degrees of All Nodes Even(Explaination+Code) | Leetcode weekly contest 324Code Bean · 8:53 · 90 views
The problem
There is an undirected graph consisting of n nodes numbered from 1 to n. You are given the integer n and a 2D array edges where edges[i] = [ai, bi] indicates that there is an edge between nodes ai and bi. The graph can be disconnected.
You can add at most two additional edges (possibly none) to this graph so that there are no repeated edges and no self-loops.
Return true if it is possible to make the degree of each node in the graph even, otherwise return false.
The degree of a node is the number of edges connected to it.
Example 1:
Input: n = 5, edges = [[1,2],[2,3],[3,4],[4,2],[1,4],[2,5]] Output: true Explanation: The above diagram shows a valid way of adding an edge. Every node in the resulting graph is connected to an even number of edges.
Example 2:
Input: n = 4, edges = [[1,2],[3,4]] Output: true Explanation: The above diagram shows a valid way of adding two edges.
Example 3:
Input: n = 4, edges = [[1,2],[1,3],[1,4]] Output: false Explanation: It is not possible to obtain a valid graph with adding at most 2 edges.
Constraints:
3 <= n <= 1052 <= edges.length <= 105edges[i].length == 21 <= ai, bi <= nai != bi- There are no repeated edges.
Approach overview
Problem Overview: You are given an undirected graph with n nodes and a list of edges. The task is to determine whether you can add at most two new edges so that every node ends up with an even degree. Multiple edges between the same pair and self-loops are not allowed.
The key observation from graph theory: a graph has all even degrees only when the number of odd-degree vertices is zero. Adding one edge flips the parity (odd/even) of exactly two vertices. This means only a few configurations of odd-degree nodes are fixable with at most two added edges.
Approach 1: Divide and Conquer Approach (O(n + m))
Start by building a graph representation using adjacency sets from the edge list. Track the degree of every node and collect all nodes with odd degree. Because each added edge changes the parity of two nodes, there are only three possible cases to check: 0 odd nodes, 2 odd nodes, or 4 odd nodes.
If there are zero odd nodes, the graph already satisfies the condition. If there are two odd nodes a and b, try directly connecting them. If an edge already exists, search for an intermediate node x such that neither (a,x) nor (b,x) exists. If four odd nodes exist, try pairing them in the three possible combinations and verify that the required edges do not already exist. Using adjacency sets allows constant-time edge existence checks. Building the graph takes O(n + m) time and the pairing checks are constant, so the overall complexity remains O(n + m) with O(n + m) space.
Approach 2: Iterative Approach Using Stack (O(n + m))
An iterative traversal can be used to compute node degrees and validate graph structure. Push nodes onto a stack and process their adjacency lists to count incident edges. This traversal ensures every vertex and edge is visited once, giving a complete degree map.
After computing degrees, push odd-degree nodes into a container and apply the same parity rules: only 0, 2, or 4 odd vertices can potentially be fixed. Use the adjacency HashSet to test candidate edges while iterating through possible pairings. The stack-based traversal avoids recursion and works well when the graph is large or when recursion limits are a concern. Time complexity is O(n + m) and space complexity is also O(n + m) due to adjacency storage and the stack.
Both approaches rely on efficient edge existence checks using a hash table structure and standard graph degree properties. Understanding the parity behavior of vertices drastically reduces the search space from exponential possibilities to a few constant checks.
Recommended for interviews: The divide-and-conquer style parity analysis is what interviewers typically expect. It shows you recognize the odd-degree constraint and can reduce the problem to checking a few valid pairings. A brute-force mindset (trying many edges) shows understanding, but recognizing the parity rule and validating with hash lookups demonstrates strong graph reasoning.
Approach 1: Divide and Conquer Approach
This approach breaks down a problem into smaller subproblems that are solved recursively. It works well when the problem can be divided into smaller, similar problems and can be combined to form the solution to the original problem.
def mergeSort(arr):
if len(arr) > 1:
mid = len(arr)//2
L = arr[:mid]
R = arr[mid:]
mergeSort(L)
mergeSort(R)
i = j = k = 0
while i < len(L) and j < len(R):
if L[i] < R[j]:
arr[k] = L[i]
i += 1
else:
arr[k] = R[j]
j += 1
k += 1
while i < len(L):
arr[k] = L[i]
i += 1
k += 1
while j < len(R):
arr[k] = R[j]
j += 1
k += 1
arr = [12, 11, 13, 5, 6, 7]
mergeSort(arr)
print("Sorted array is:")
print(arr)public class MergeSort {
static void merge(int arr[], int left, int middle, int right) {
int n1 = middle - left + 1;
int n2 = right - middle;
int L[] = new int[n1];
int R[] = new int[n2];
for (int i = 0; i < n1; ++i)
L[i] = arr[left + i];
for (int j = 0; j < n2; ++j)
R[j] = arr[middle + 1 + j];
int i = 0, j = 0;
int k = left;
while (i < n1 && j < n2) {
if (L[i] <= R[j]) {
arr[k] = L[i];
i++;
} else {
arr[k] = R[j];
j++;
}
k++;
}
while (i < n1) {
arr[k] = L[i];
i++;
k++;
}
while (j < n2) {
arr[k] = R[j];
j++;
k++;
}
}
static void mergeSort(int arr[], int left, int right) {
if (left < right) {
int middle = left + (right - left) / 2;
mergeSort(arr, left, middle);
mergeSort(arr, middle + 1, right);
merge(arr, left, middle, right);
}
}
public static void main(String[] args) {
int arr[] = {12, 11, 13, 5, 6, 7};
mergeSort(arr, 0, arr.length - 1);
System.out.println("Sorted array");
for (int i = 0; i < arr.length; ++i)
System.out.print(arr[i] + " ");
}
}#include <iostream>
void merge(int arr[], int left, int middle, int right) {
int n1 = middle - left + 1;
int n2 = right - middle;
int L[n1], R[n2];
for (int i = 0; i < n1; i++)
L[i] = arr[left + i];
for (int j = 0; j < n2; j++)
R[j] = arr[middle + 1 + j];
int i = 0;
int j = 0;
int k = left;
while (i < n1 && j < n2) {
if (L[i] <= R[j]) {
arr[k] = L[i];
i++;
} else {
arr[k] = R[j];
j++;
}
k++;
}
while (i < n1) {
arr[k] = L[i];
i++;
k++;
}
while (j < n2) {
arr[k] = R[j];
j++;
k++;
}
}
void mergeSort(int arr[], int left, int right) {
if (left < right) {
int middle = left + (right - left) / 2;
mergeSort(arr, left, middle);
mergeSort(arr, middle + 1, right);
merge(arr, left, middle, right);
}
}
int main() {
int arr[] = {12, 11, 13, 5, 6, 7};
int arr_size = sizeof(arr) / sizeof(arr[0]);
mergeSort(arr, 0, arr_size - 1);
std::cout << "Sorted array is: \n";
for (int i = 0; i < arr_size; i++)
std::cout << arr[i] << " ";
return 0;
}function mergeSort(arr) {
if (arr.length < 2) {
return arr;
}
const mid = Math.floor(arr.length / 2);
const left = arr.slice(0, mid);
const right = arr.slice(mid);
return merge(mergeSort(left), mergeSort(right));
}
function merge(left, right) {
let result = [],
leftIndex = 0,
rightIndex = 0;
while (leftIndex < left.length && rightIndex < right.length) {
if (left[leftIndex] < right[rightIndex]) {
result.push(left[leftIndex]);
leftIndex++;
} else {
result.push(right[rightIndex]);
rightIndex++;
}
}
return result
.concat(left.slice(leftIndex))
.concat(right.slice(rightIndex));
}
const arr = [12, 11, 13, 5, 6, 7];
console.log('Sorted array is:', mergeSort(arr));#include <stdio.h>
void merge(int arr[], int left, int middle, int right) {
int n1 = middle - left + 1;
int n2 = right - middle;
int L[n1], R[n2];
for (int i = 0; i < n1; i++)
L[i] = arr[left + i];
for (int j = 0; j < n2; j++)
R[j] = arr[middle + 1 + j];
int i = 0;
int j = 0;
int k = left;
while (i < n1 && j < n2) {
if (L[i] <= R[j]) {
arr[k] = L[i];
i++;
} else {
arr[k] = R[j];
j++;
}
k++;
}
while (i < n1) {
arr[k] = L[i];
i++;
k++;
}
while (j < n2) {
arr[k] = R[j];
j++;
k++;
}
}
void mergeSort(int arr[], int left, int right) {
if (left < right) {
int middle = left + (right - left) / 2;
mergeSort(arr, left, middle);
mergeSort(arr, middle + 1, right);
merge(arr, left, middle, right);
}
}
int main() {
int arr[] = {12, 11, 13, 5, 6, 7};
int arr_size = sizeof(arr) / sizeof(arr[0]);
mergeSort(arr, 0, arr_size - 1);
printf("Sorted array is: \n");
for (int i = 0; i < arr_size; i++)
printf("%d ", arr[i]);
return 0;
}using System;
class MergeSort {
static void merge(int[] arr, int left, int mid, int right) {
int n1 = mid - left + 1;
int n2 = right - mid;
int[] L = new int[n1];
int[] R = new int[n2];
Array.Copy(arr, left, L, 0, n1);
Array.Copy(arr, mid + 1, R, 0, n2);
int i = 0, j = 0;
int k = left;
while (i < n1 && j < n2) {
if (L[i] <= R[j]) {
arr[k] = L[i];
i++;
} else {
arr[k] = R[j];
j++;
}
k++;
}
while (i < n1) {
arr[k] = L[i];
i++;
k++;
}
while (j < n2) {
arr[k] = R[j];
j++;
k++;
}
}
static void mergeSort(int[] arr, int left, int right) {
if (left < right) {
int mid = left + (right - left) / 2;
mergeSort(arr, left, mid);
mergeSort(arr, mid + 1, right);
merge(arr, left, mid, right);
}
}
public static void Main() {
int[] arr = { 12, 11, 13, 5, 6, 7 };
mergeSort(arr, 0, arr.Length - 1);
Console.WriteLine("Sorted array is");
foreach (int i in arr) {
Console.Write(i + " ");
}
}
}The Python implementation of merge sort follows the same recursion pattern. The array is split, recursively sorted, and merged back.
Time Complexity: O(n log n). Space Complexity: O(n).
Approach 2: Iterative Approach Using Stack
An iterative approach can be ideal for avoiding the memory overhead of recursion. By using a stack to simulate the call stack, we can perform merge sort iteratively. This trades additional stack space for a potentially more memory-efficient solution.
def merge(arr, l, m, r):
n1 = m - l + 1
n2 = r - m
L = arr[l:l+n1]
R = arr[m+1:m+1+n2]
i = j = 0
k = l
while i < n1 and j < n2:
if L[i] <= R[j]:
arr[k] = L[i]
i += 1
else:
arr[k] = R[j]
j += 1
k += 1
while i < n1:
arr[k] = L[i]
i += 1
k += 1
while j < n2:
arr[k] = R[j]
j += 1
k += 1
def iterativeMergeSort(arr, n):
curr_size = 1
while curr_size <= n-1:
left_start = 0
while left_start < n-1:
mid = min((left_start + curr_size - 1), (n-1))
right_end = min((left_start + 2*curr_size - 1), (n-1))
merge(arr, left_start, mid, right_end)
left_start += 2*curr_size
curr_size = 2*curr_size
arr = [12, 11, 13, 5, 6, 7]
iterativeMergeSort(arr, len(arr))
print("Sorted array is:", arr)import java.util.Arrays;
class IterativeMergeSort {
void merge(int[] arr, int l, int m, int r) {
int n1 = m - l + 1;
int n2 = r - m;
int[] L = new int[n1];
int[] R = new int[n2];
System.arraycopy(arr, l, L, 0, n1);
System.arraycopy(arr, m + 1, R, 0, n2);
int i = 0, j = 0, k = l;
while (i < n1 && j < n2) {
if (L[i] <= R[j]) {
arr[k] = L[i];
i++;
} else {
arr[k] = R[j];
j++;
}
k++;
}
while (i < n1) {
arr[k] = L[i];
i++;
k++;
}
while (j < n2) {
arr[k] = R[j];
j++;
k++;
}
}
void iterativeMergeSort(int[] arr, int n) {
for (int curr_size = 1; curr_size <= n-1; curr_size = 2*curr_size) {
for (int left_start = 0; left_start < n-1; left_start += 2*curr_size) {
int mid = Math.min(left_start + curr_size - 1, n-1);
int right_end = Math.min(left_start + 2*curr_size - 1, n-1);
merge(arr, left_start, mid, right_end);
}
}
}
public static void main(String args[]) {
int[] arr = {12, 11, 13, 5, 6, 7};
IterativeMergeSort ob = new IterativeMergeSort();
ob.iterativeMergeSort(arr, arr.length);
System.out.println("Sorted array");
System.out.println(Arrays.toString(arr));
}
}#include <iostream>
#include <vector>
void merge(std::vector<int>& arr, int l, int m, int r) {
int n1 = m - l + 1;
int n2 = r - m;
std::vector<int> L(n1);
std::vector<int> R(n2);
for (int i = 0; i < n1; i++)
L[i] = arr[l + i];
for (int j = 0; j < n2; j++)
R[j] = arr[m + 1 + j];
int i = 0, j = 0, k = l;
while (i < n1 && j < n2) {
if (L[i] <= R[j]) {
arr[k] = L[i];
i++;
} else {
arr[k] = R[j];
j++;
}
k++;
}
while (i < n1) {
arr[k] = L[i];
i++;
k++;
}
while (j < n2) {
arr[k] = R[j];
j++;
k++;
}
}
void iterativeMergeSort(std::vector<int>& arr, int n) {
for (int curr_size = 1; curr_size <= n-1; curr_size = 2*curr_size) {
for (int left_start = 0; left_start < n-1; left_start += 2*curr_size) {
int mid = std::min(left_start + curr_size - 1, n-1);
int right_end = std::min(left_start + 2*curr_size - 1, n-1);
merge(arr, left_start, mid, right_end);
}
}
}
int main() {
std::vector<int> arr = {12, 11, 13, 5, 6, 7};
iterativeMergeSort(arr, arr.size());
std::cout << "Sorted array is \n";
for (int i = 0; i < arr.size(); i++)
std::cout << arr[i] << " ";
return 0;
}function merge(arr, l, m, r) {
const n1 = m - l + 1;
const n2 = r - m;
const L = arr.slice(l, m + 1);
const R = arr.slice(m + 1, r + 1);
let i = 0, j = 0, k = l;
while (i < n1 && j < n2) {
if (L[i] <= R[j]) {
arr[k] = L[i];
i++;
} else {
arr[k] = R[j];
j++;
}
k++;
}
while (i < n1) {
arr[k] = L[i];
i++;
k++;
}
while (j < n2) {
arr[k] = R[j];
j++;
k++;
}
}
function iterativeMergeSort(arr) {
const n = arr.length;
for (let curr_size = 1; curr_size <= n - 1; curr_size = 2 * curr_size) {
for (let left_start = 0; left_start < n - 1; left_start += 2 * curr_size) {
const mid = Math.min(left_start + curr_size - 1, n - 1);
const right_end = Math.min(left_start + 2 * curr_size - 1, n - 1);
merge(arr, left_start, mid, right_end);
}
}
}
const arr = [12, 11, 13, 5, 6, 7];
iterativeMergeSort(arr);
console.log('Sorted array:', arr);#include <stdio.h>
#include <stdlib.h>
void merge(int arr[], int l, int m, int r) {
int i, j, k;
int n1 = m - l + 1;
int n2 = r - m;
int *L = (int *)malloc(n1 * sizeof(int));
int *R = (int *)malloc(n2 * sizeof(int));
for (i = 0; i < n1; i++)
L[i] = arr[l + i];
for (j = 0; j < n2; j++)
R[j] = arr[m + 1 + j];
i = 0;
j = 0;
k = l;
while (i < n1 && j < n2) {
if (L[i] <= R[j]) {
arr[k] = L[i];
i++;
} else {
arr[k] = R[j];
j++;
}
k++;
}
while (i < n1) {
arr[k] = L[i];
i++;
k++;
}
while (j < n2) {
arr[k] = R[j];
j++;
k++;
}
free(L);
free(R);
}
void iterativeMergeSort(int arr[], int n) {
int curr_size;
int left_start;
for (curr_size = 1; curr_size <= n-1; curr_size = 2*curr_size) {
for (left_start = 0; left_start < n-1; left_start += 2*curr_size) {
int mid = min(left_start + curr_size - 1, n-1);
int right_end = min(left_start + 2*curr_size - 1, n-1);
merge(arr, left_start, mid, right_end);
}
}
}
int main() {
int arr[] = {12, 11, 13, 5, 6, 7};
int n = sizeof(arr)/sizeof(arr[0]);
iterativeMergeSort(arr, n);
printf("Sorted array is \n");
for (int i=0; i < n; i++)
printf("%d ", arr[i]);
return 0;
}
int min(int x, int y) { return (x<y)? x :y; }using System;
class IterativeMergeSort {
static void Merge(int[] arr, int l, int m, int r) {
int n1 = m - l + 1;
int n2 = r - m;
int[] L = new int[n1];
int[] R = new int[n2];
Array.Copy(arr, l, L, 0, n1);
Array.Copy(arr, m + 1, R, 0, n2);
int i = 0, j = 0, k = l;
while (i < n1 && j < n2) {
if (L[i] <= R[j]) {
arr[k] = L[i];
i++;
} else {
arr[k] = R[j];
j++;
}
k++;
}
while (i < n1) {
arr[k] = L[i];
i++;
k++;
}
while (j < n2) {
arr[k] = R[j];
j++;
k++;
}
}
static void IterativeMergeSortAlgo(int[] arr, int n) {
for (int curr_size = 1; curr_size <= n-1; curr_size = 2*curr_size) {
for (int left_start = 0; left_start < n-1; left_start += 2*curr_size) {
int mid = Math.Min(left_start + curr_size - 1, n-1);
int right_end = Math.Min(left_start + 2*curr_size - 1, n-1);
Merge(arr, left_start, mid, right_end);
}
}
}
public static void Main() {
int[] arr = { 12, 11, 13, 5, 6, 7 };
IterativeMergeSortAlgo(arr, arr.Length);
Console.WriteLine("Sorted array is: ");
Console.WriteLine(string.Join(" ", arr));
}
}In Python, iterative merge sort makes use of while loops to drive the merge and sort on increasing subarray sizes without stack usage for recursion.
Time Complexity: O(n log n). Space Complexity: O(n).
Approach 3: Case Analysis
We first build the graph g using edges, and then find all nodes with odd degrees, denoted as vs.
If the length of vs is 0, it means all nodes in the graph g have even degrees, so we return true.
If the length of vs is 2, it means there are two nodes with odd degrees in the graph g. If we can directly connect these two nodes with an edge, making all nodes in the graph g have even degrees, we return true. Otherwise, if we can find a third node c such that we can connect a and c, and b and c, making all nodes in the graph g have even degrees, we return true. Otherwise, we return false.
If the length of vs is 4, we enumerate all possible pairs and check if any combination meets the conditions. If so, we return true; otherwise, we return false.
In other cases, we return false.
The time complexity is O(n + m), and the space complexity is O(n + m). Where n and m are the number of nodes and edges, respectively.
func isPossible(n int, edges [][]int) bool {
g := make([]map[int]bool, n+1)
for _, e := range edges {
a, b := e[0], e[1]
if g[a] == nil {
g[a] = map[int]bool{}
}
if g[b] == nil {
g[b] = map[int]bool{}
}
g[a][b], g[b][a] = true, true
}
vs := []int{}
for i := 1; i <= n; i++ {
if len(g[i])%2 == 1 {
vs = append(vs, i)
}
}
if len(vs) == 0 {
return true
}
if len(vs) == 2 {
a, b := vs[0], vs[1]
if !g[a][b] {
return true
}
for c := 1; c <= n; c++ {
if a != c && b != c && !g[a][c] && !g[c][b] {
return true
}
}
return false
}
if len(vs) == 4 {
a, b, c, d := vs[0], vs[1], vs[2], vs[3]
if !g[a][b] && !g[c][d] {
return true
}
if !g[a][c] && !g[b][d] {
return true
}
if !g[a][d] && !g[b][c] {
return true
}
return false
}
return false
}Complexity comparison
| Approach | Complexity |
|---|---|
| Divide and Conquer Approach | Time Complexity: O(n log n). Space Complexity: O(n). |
| Iterative Approach Using Stack | Time Complexity: O(n log n). Space Complexity: O(n). |
| Case Analysis | – |
Complexity analysis
| Approach | Time | Space | When to Use |
|---|---|---|---|
| Divide and Conquer Degree Analysis | O(n + m) | O(n + m) | Best general solution. Quickly checks odd-degree configurations using adjacency hash sets. |
| Iterative Approach Using Stack | O(n + m) | O(n + m) | Useful when performing explicit graph traversal or avoiding recursion while computing node degrees. |
Frequently asked questions
Is Add Edges to Make Degrees of All Nodes Even easy or hard?
The problem is classified as Hard because it requires recognizing graph parity constraints and reducing the search space to a few valid configurations. Once the odd-degree insight is understood, the implementation becomes straightforward with hash sets.
Add Edges to Make Degrees of All Nodes Even Python/Java solution
Implement the solution by building an adjacency set for each node, computing degrees, and storing odd-degree vertices. Then test valid pairings depending on whether there are two or four odd nodes. This logic works consistently across Python, Java, C++, and other languages.
How to solve Add Edges to Make Degrees of All Nodes Even in O(n)?
Build adjacency sets and compute degrees for all nodes while iterating through the edges. Collect nodes with odd degree and handle three cases: 0, 2, or 4 odd nodes. Validate whether the required edges can be added without duplicates using constant-time hash lookups.
What is the best approach for Add Edges to Make Degrees of All Nodes Even?
The optimal approach analyzes the parity of node degrees in the graph. Count nodes with odd degree and check whether they can be fixed by adding at most two edges. Using adjacency hash sets allows constant-time edge existence checks, resulting in an overall time complexity of O(n + m).
Is Add Edges to Make Degrees of All Nodes Even asked at Google/Amazon/Meta?
Graph parity and degree manipulation problems frequently appear in interviews at companies like Google, Amazon, and Meta. Variations often test understanding of Eulerian graph properties, adjacency sets, and efficient edge validation.
What data structure is used in Add Edges to Make Degrees of All Nodes Even?
The solution uses graph adjacency sets implemented with hash tables. These structures store neighbors of each node and allow O(1) average-time checks to determine whether an edge already exists between two vertices.
What is the time complexity of Add Edges to Make Degrees of All Nodes Even?
The optimal solution runs in O(n + m) time, where n is the number of nodes and m is the number of edges. Building adjacency sets and counting node degrees takes linear time, and the final parity checks involve only a few constant combinations.
