Satisfiability of Equality Equations
Keep one group per letter. Join every == pair first, then check each != against the finished groups. Two letters with the same root are linked by a chain of ==, so a != between them is a contradiction.
After every == is merged, two letters are forced equal exactly when they share a root, so a != between them is a contradiction.
Problem
You get a list of equations between single lowercase letters. Each equation is either x==y, which says x and y must be equal, or x!=y, which says they must be different.
Return true if you can give every letter a value so that all the equations hold at the same time. Return false if the equations contradict each other.
equations: a list of 4-character strings. Each one is a letter, then == or !=, then a letter. For example "a==b".
true if all equations can hold together, false otherwise.
a equals b, so b cannot be different from a.
Both equations say the same thing, so they agree.
a equals b and c equals a, so b equals c. That breaks b!=c.
c equals itself, b and d are linked to each other only, and x and z are unrelated.
- • 1 <= equations.length <= 500
- • equations[i].length == 4
- • equations[i][0] is a lowercase letter
- • equations[i][1] is either '=' or '!'
- • equations[i][2] is '='
- • equations[i][3] is a lowercase letter
First, think yourself
Before opening any solution, try to answer these on paper. Use hints only when stuck — each hint is counted.
- 1.
An
==links two letters together. Which letters end up linked once I follow every==I have? - 2.
Suppose the list is
a!=b, thena==c, thenc==b. Can I decidea!=bthe moment I read it? Why not? - 3.
Which structure already keeps track of sets of linked items, and how do I ask whether two items are in the same set?
- 4.
Does
a!=aneed its own special case, or can the same check handle it? - 5.
What do I need to know about the whole list before I can judge a single
!=?
Brute force approach
Optimized approach
Why does this algorithm work?
Dry run
All approaches compared
| Approach | Idea | Time | Space |
|---|---|---|---|
| Brute Force | BFS over the == links from one letter, once for each != | O(N · (26 + N)) | O(26 + N) |
| Optimal | Union-Find: merge every == pair, then fail a != whose letters share a root | O(N · α) | O(1) |
Why does this belong to this pattern?
- “x == y”Joins x and y into one group. Equal is transitive, so the group grows along chains of `==`.
- “x != y”A rule to check against the finished groups, not something to union.
- “can all the equations hold together”One contradiction is enough to return false, and no contradiction means true.
This is the grouping by equivalence sub-pattern, where == links become unions. What makes this one different from its neighbours is order: the check for != must wait until every == has been merged, because a later == can join two letters that an earlier != looked at. Accounts Merge only needs the unions. Here the != pairs are a test on the finished groups, so they run second. Compare roots with find(x) == find(y), not with parent[x] == parent[y], because a letter can sit two steps below its root.
Don't make this mistake
This is the pattern-confusion trap. On ["a!=b", "a==c", "c==b"] the first equation is checked while a and b are still separate, so nothing fails. Then a==c and c==b join a, c and b into one group, but the loop has already passed a!=b. It returns true, and the answer is false.
A letter is never different from itself, so ["a!=a"] must return false. The plain find check already does that, since find(a) == find(a). The extra e[0] != e[3] test turns it into true.
parent[x] is only one step up, not the group name. On ["a==b", "c==d", "b==d", "a!=d"] the unions leave parent[a] = a and parent[d] = c, so the parent check says a and d differ and returns true. But d sits under c, and c sits under a, so find(d) = a and the answer is false.
Want to implement this?
Write it yourself on LeetCode, then come back and compare your code with the solutions above.
Open coding workspaceHow this concept connects to System Design & C++ Systems
Top engineering interviews test whether you understand how algorithms like Union-Find (DSU) translate into production architectures and low-level memory mechanics.
Foundations: Object-Oriented Principles in C++23
Class invariants, pure virtual interfaces, and RAII smart pointers.
Food Delivery System (Zomato Architecture)
Real-world machine coding application of algorithms and design patterns.
Pointers vs References Deep Dive
Pointer arithmetic and memory layout under the hood.
Virtual Method Table (vtable) & Memory Layout
Polymorphism, vptr overhead, and multiple inheritance in memory.