Satisfiability of Equality Equations
You are given an array of strings equations that represent relationships between variables where each string equationsi is of length 4 and takes one of two forms: "xi==yi" or "xi!=yi". Return true if it is possible to assign integers to variable names so as to satisfy all the given equations, or false otherwise. Union every "==" pair first, then check every "!=" pair — if the two sides already share a root , the equations contradict each other.
Constraints
- 1 ≤ equations.length ≤ 500
- equationsi.length == 4
- equationsi[0] and equationsi[3] are lowercase letters
Example
equations = ["a==b","b!=a"]falseExplanation The first equation says a and b are equal, but the second says they are not — a contradiction.
Union all == pairs first, then check every != pair
"a==b": union a and b. They now share a root.
What happens in this step
union(a, b)
find(a) → a find(b) → b
roots differ → union: parent[a] = b
parent: { a: a, b: b } → { a: b, b: b }
a and b are merged into one group, represented by root b.Steps to visualize
- Make one pass over the equations, unioning both sides of every "==" equation.
- Make a second pass over the equations, and for every "!=" equation compare find on both sides.
- If any "!=" pair already shares a root from the first pass, the equations are unsatisfiable.
- If no "!=" pair ever matches, every equation can be satisfied.
Walk through the code
Same walkthrough, now with the code. Press Next to move one step and watch which lines run.
"a==b": union a and b. They now share a root.
What happens in this step
union(a, b)
find(a) → a find(b) → b
roots differ → union: parent[a] = b
parent: { a: a, b: b } → { a: b, b: b }
a and b are merged into one group, represented by root b.Solution
function equationsPossible(equations) {
const parent = {};
function ensure(x) {
if (!(x in parent)) {
parent[x] = x;
}
}
function find(x) {
ensure(x);
while (parent[x] !== x) {
parent[x] = parent[parent[x]];
x = parent[x];
}
return x;
}
function union(a, b) {
const rootA = find(a);
const rootB = find(b);
if (rootA !== rootB) {
parent[rootA] = rootB;
}
}
for (const eq of equations) {
if (eq[1] === '=') {
union(eq[0], eq[3]);
}
}
for (const eq of equations) {
if (eq[1] === '!') {
if (find(eq[0]) === find(eq[3])) {
return false;
}
}
}
return true;
}- Time
- O(n · α(n))
- Space
- O(1) — at most 26 variables
Test cases
| Input | Expected | Covers |
|---|---|---|
equations = ["a==b","b!=a"] | false | example from the docstring |
equations = ["b==a","a==b"] | true | the same equality stated twice with sides swapped |
equations = ["a==b","b==c","a==c"] | true | a chain of equalities with a consistent closing equation |
equations = ["a==b","b!=c","c==a"] | false | a contradiction only visible once all three variables are linked |
equations = ["a==a"] | true | a variable declared equal to itself is always satisfiable |
equations = ["a!=a"] | false | a variable declared unequal to itself can never be satisfied |
equations = ["a==b","c==d","a!=c"] | true | two separate equality groups with no shared variable stay consistent |