题目描述
给定一个由表示变量之间关系的字符串方程组成的数组,每个字符串方程 equations[i] 的长度为 4,并采用两种不同的形式之一:“a==b” 或 “a!=b”。在这里,a 和 b 是小写字母(不一定不同),表示单字母变量名。
只有当可以将整数分配给变量名,以便满足所有给定的方程时才返回 true,否则返回 false。
示例 1:
输入:[“a==b”,“b!=a”]
输出:false
解释:如果我们指定,a = 1 且 b = 1,那么可以满足第一个方程,但无法满足第二个方程。没有办法分配变量同时满足这两个方程。
示例 2:
输入:[“ba”,“ab”]
输出:true
解释:我们可以指定 a = 1 且 b = 1 以满足满足这两个方程。
示例 3:
输入:[“ab”,“bc”,“a==c”]
输出:true
示例 4:
输入:[“ab”,“b!=c”,“ca”]
输出:false
示例 5:
输入:[“cc”,“bd”,“x!=z”]
输出:true
提示:
- 1 <= equations.length <= 500
- equations [i].length == 4
- equations[i][0] 和 equations[i][3] 是小写字母
- equations[i][1] 要么是 ‘=’,要么是 ‘!’
- equations[i][2] 是 ‘=’
题目链接:https://leetcode-cn.com/problems/satisfiability-of-equality-equations/
对象声明
/**
* 待检查不等式
*/
class NonEquation {
final char ch1;
final char ch2;
NonEquation(char ch1, char ch2) {
this.ch1 = ch1;
this.ch2 = ch2;
}
}
解题思路
一、并查集
首先遍历所有的表达式,如果是等式则把两个变量指向同一个根,即把两个变量对应的集合进行合并,如果是不等式则把不等式放入待检查的队列中。当表达式遍历完成后,开始检查队列中的不等式,如果不等式的两个变量 ch1,ch2 有相同的根,即两个变量在同一个集合中,说明 ch1 == ch2,那么表达式 ch1 != ch2 就不成立,直接返回 false,如果检查完成,所有的不等式都成立,则返回 true。
public boolean equationsPossible(String[] equations) {
Map<Character, Character> data = new HashMap<>();
Map<Character, Integer> level = new HashMap<>();
Queue<NonEquation> queue = new LinkedList<>();
for (String equation : equations) {
char ch1 = equation.charAt(0);
char ch2 = equation.charAt(3);
char symbol = equation.charAt(1);
if (symbol == '=') {
if (ch1 == ch2) {
continue;
}
union(ch1, ch2, data, level);
} else {
if (ch1 == ch2) {
return false;
}
queue.offer(new NonEquation(ch1, ch2));
}
}
while (!queue.isEmpty()) {
NonEquation nonEquation = queue.poll();
char root1 = find(nonEquation.ch1, data);
char root2 = find(nonEquation.ch2, data);
if (root1 == root2) {
return false;
}
}
return true;
}
public void union(char ch1, char ch2, Map<Character, Character> data, Map<Character, Integer> level) {
char root1 = find(ch1, data);
char root2 = find(ch2, data);
if (root1 == root2) {
return;
}
int level1 = level.getOrDefault(root1, 0);
int level2 = level.getOrDefault(root2, 0);
if (level1 > level2) {
data.put(root2, root1);
} else if (level1 < level2) {
data.put(root1, root2);
} else {
data.put(root1, root2);
level.put(root2, level2 + 1);
}
}
public char find(char ch, Map<Character, Character> data) {
char value = ch;
while (data.get(value) != null) {
value = data.get(value);
}
return value;
}
二、深度优先搜索+回溯算法
首先定义一个邻接矩阵 matrix[26][26],保存顶点之间的连通性,然后开始遍历所有的表达式,如果是等式则认为两个变量之间是连通的,将 matrix[ch1][ch2]设置为 true,如果是不等式则把不等式放入待检查的队列中。当表达式遍历完成后,开始检查队列中的不等式,使用深度搜索去查找 ch1 和 ch2 之前是否存在一条路径,如果不等式的两个变量 ch1,ch2 之前存在一条路径,即 ch1 和 ch2 之间是连通的,则说明 ch1 == ch2,那么表达式 ch1 != ch2 就不成立,直接返回 false,如果检查完成,所有的不等式都成立,则返回 true。
public boolean equationsPossible(String[] equations) {
boolean[][] matrix = new boolean[26][26];
Queue<NonEquation> queue = new LinkedList<>();
for (String equation : equations) {
char ch1 = equation.charAt(0);
char ch2 = equation.charAt(3);
char symbol = equation.charAt(1);
if (symbol == '=') {
if (ch1 == ch2) {
continue;
}
matrix[ch1 - 'a'][ch2 - 'a'] = true;
matrix[ch2 - 'a'][ch1 - 'a'] = true;
} else {
if (ch1 == ch2) {
return false;
}
queue.offer(new NonEquation(ch1, ch2));
}
}
while (!queue.isEmpty()) {
NonEquation node = queue.poll();
boolean[][] visited = new boolean[matrix.length][matrix[0].length];
boolean res = equationsPossible_dfs(matrix, node.ch1 - 'a', node.ch2 - 'a', visited);
if (!res) {
return false;
}
}
return true;
}
public boolean equationsPossible_dfs(boolean[][] matrix, int i, int target, boolean[][] visited) {
for (int k = 0; k < matrix[0].length; k++) {
if (!matrix[i][k]) {
continue;
}
if (visited[i][k] || visited[k][i]) {
continue;
}
if (k == target) {
return false;
}
visited[i][k] = true;
boolean res = equationsPossible_dfs(matrix, k, target, visited);
visited[i][k] = false;
if (!res) {
return false;
}
}
return true;
}
视频讲解
- 在 YouTube 上查看请点击https://youtu.be/p0QnHcQBVK0
- 在 B 站上查看请点击https://www.bilibili.com/video/BV1Mt4y197wc
- 在西瓜视频上查看请点击https://www.ixigua.com/i6838141591039771140