You are given a list of equations representing relationships between variables. Each equation is of the form a == b
or a != b
, where a
and b
are variable names consisting of lowercase letters. Your task is to determine if it is possible to assign values to the variables such that all equations are satisfied.
Key constraints:
"a==b"
or "a!=b"
.
The function should return true
if it is possible to satisfy all equations, and false
otherwise.
At first glance, we might think to check every possible assignment of values to variables to see if all equations can be satisfied. However, with up to 500 equations and potentially 26 variables, this brute-force approach is computationally infeasible.
Instead, let's think in terms of relationships:
==
mean two variables must have the same value.!=
mean two variables must have different values.This naturally leads us to use the Union-Find (Disjoint Set Union) data structure, which efficiently tracks which variables are in the same group.
We'll use the Union-Find data structure to efficiently group variables that must be equal. The algorithm proceeds in two main steps:
==
) equations:
a==b
, merge the sets containing a
and b
. This means they must be equal.!=
) equations:
a!=b
, check if a
and b
are in the same set.false
.true
.Why Union-Find? Because it allows us to efficiently merge sets and check if two variables are in the same set, both in nearly constant time.
Implementation Details:
==
equations, then check for contradictions with !=
equations.
Example Input: ["a==b", "b!=c", "c==a"]
a==b
: Union 'a' and 'b'. Now, 'a' and 'b' are in the same set.c==a
: Union 'c' and 'a'. Now, 'a', 'b', and 'c' are in the same set.b!=c
: Are 'b' and 'c' in the same set? Yes, because both are connected through 'a'.false
.
Another Example: ["a==b", "b!=c"]
a==b
: Union 'a' and 'b'.b!=c
: 'b' and 'c' are not in the same set, so no contradiction. Return true
.By modeling the problem as a set of equivalence classes, we can efficiently solve it using the Union-Find data structure. We first group variables that must be equal, then check for any contradictions among variables that must be unequal. This approach is both elegant and efficient, turning a seemingly complex logic problem into a matter of set management.
class Solution:
def equationsPossible(self, equations):
parent = [i for i in range(26)]
def find(x):
if parent[x] != x:
parent[x] = find(parent[x])
return parent[x]
def union(x, y):
parent[find(x)] = find(y)
# First, process all '==' equations
for eq in equations:
if eq[1:3] == '==':
a = ord(eq[0]) - ord('a')
b = ord(eq[3]) - ord('a')
union(a, b)
# Then, process all '!=' equations
for eq in equations:
if eq[1:3] == '!=':
a = ord(eq[0]) - ord('a')
b = ord(eq[3]) - ord('a')
if find(a) == find(b):
return False
return True
class Solution {
public:
int find(vector<int>& parent, int x) {
if (parent[x] != x)
parent[x] = find(parent, parent[x]);
return parent[x];
}
void unite(vector<int>& parent, int x, int y) {
parent[find(parent, x)] = find(parent, y);
}
bool equationsPossible(vector<string>& equations) {
vector<int> parent(26);
for (int i = 0; i < 26; ++i) parent[i] = i;
// First, process all '==' equations
for (string& eq : equations) {
if (eq[1] == '=') {
int a = eq[0] - 'a', b = eq[3] - 'a';
unite(parent, a, b);
}
}
// Then, process all '!=' equations
for (string& eq : equations) {
if (eq[1] == '!') {
int a = eq[0] - 'a', b = eq[3] - 'a';
if (find(parent, a) == find(parent, b))
return false;
}
}
return true;
}
};
class Solution {
public boolean equationsPossible(String[] equations) {
int[] parent = new int[26];
for (int i = 0; i < 26; i++) parent[i] = i;
for (String eq : equations) {
if (eq.charAt(1) == '=') {
int a = eq.charAt(0) - 'a';
int b = eq.charAt(3) - 'a';
union(parent, a, b);
}
}
for (String eq : equations) {
if (eq.charAt(1) == '!') {
int a = eq.charAt(0) - 'a';
int b = eq.charAt(3) - 'a';
if (find(parent, a) == find(parent, b))
return false;
}
}
return true;
}
private int find(int[] parent, int x) {
if (parent[x] != x)
parent[x] = find(parent, parent[x]);
return parent[x];
}
private void union(int[] parent, int x, int y) {
parent[find(parent, x)] = find(parent, y);
}
}
var equationsPossible = function(equations) {
const parent = new Array(26);
for (let i = 0; i < 26; i++) parent[i] = i;
function find(x) {
if (parent[x] !== x) parent[x] = find(parent[x]);
return parent[x];
}
function union(x, y) {
parent[find(x)] = find(y);
}
// First, process all '==' equations
for (let eq of equations) {
if (eq[1] === '=') {
const a = eq.charCodeAt(0) - 97;
const b = eq.charCodeAt(3) - 97;
union(a, b);
}
}
// Then, process all '!=' equations
for (let eq of equations) {
if (eq[1] === '!') {
const a = eq.charCodeAt(0) - 97;
const b = eq.charCodeAt(3) - 97;
if (find(a) === find(b)) return false;
}
}
return true;
};