一天一大 leet (990. 等式方程的可满足性)
程序员文章站
2022-05-07 23:09:46
...
20200608
题目(难度:困难):
给定一个由表示变量之间关系的字符串方程组成的数组,每个字符串方程 equations[i] 的长度为 4,并采用两种不同的形式之一:“a==b” 或 “a!=b”。在这里,a 和 b 是小写字母(不一定不同),表示单字母变量名。
只有当可以将整数分配给变量名,以便满足所有给定的方程时才返回 true,否则返回 false。
示例
- 示例 1
输入:["a==b","b!=a"]
输出:false
解释:如果我们指定,a = 1 且 b = 1,那么可以满足第一个方程,但无法满足第二个方程。没有办法分配变量同时满足这两个方程。
- 示例 2
输出:["b==a","a==b"]
输入:true
解释:我们可以指定 a = 1 且 b = 1 以满足满足这两个方程。
- 示例 3
输入:["a==b","b==c","a==c"]
输出:true
- 示例 4
输入:["a==b","b!=c","c==a"]
输出:false
- 示例 5
输入:["c==c","b==d","x!=z"]
输出:true
提示
- 1 <= equations.length <= 500
- equations[i].length == 4
- equations[i][0] 和 equations[i][3] 是小写字母
- equations[i][1] 要么是 ‘=’,要么是 ‘!’
- equations[i][2] 是 ‘=’
抛砖引玉
- 提示中说 equations[i][3] 是小写字母则可以使用字母初始化一个长度伪 26 值不同是数组 parent
- 遍历等式运算,根据等式中出现的变量把对象的 parent 值置成相同
- 遍历不等式运算,如果不等式两边的字母对应的 parent 相同则返回 false
- 没有触发 false 这默认 true
/**
* @param {string[]} equations
* @return {boolean}
*/
var equationsPossible = function (equations) {
var parent = []
var len = equations.length
for (var i = 0; i < 26; i++) {
parent[i] = i
}
for (var index = 0; index < equations.length; index++) {
if (equations[index][1] === '=') {
var index1 = equations[index].charCodeAt(0) - 97
var index2 = equations[index].charCodeAt(3) - 97
union(parent, index1, index2)
}
}
for (var index = 0; index < equations.length; index++) {
if (equations[index][1] === '!') {
var index1 = equations[index].charCodeAt(0) - 97
var index2 = equations[index].charCodeAt(3) - 97
if (find(parent, index1) == find(parent, index2)) {
return false
}
}
}
return true
function union(parent, index1, index2) {
parent[find(parent, index1)] = find(parent, index2)
}
function find(parent, index) {
while (parent[index] != index) {
parent[index] = parent[parent[index]]
index = parent[index]
}
return index
}
}
官方答案
class Solution {
public boolean equationsPossible(String[] equations) {
int length = equations.length;
int[] parent = new int[26];
for (int i = 0; i < 26; i++) {
parent[i] = i;
}
for (String str : equations) {
if (str.charAt(1) == '=') {
int index1 = str.charAt(0) - 'a';
int index2 = str.charAt(3) - 'a';
union(parent, index1, index2);
}
}
for (String str : equations) {
if (str.charAt(1) == '!') {
int index1 = str.charAt(0) - 'a';
int index2 = str.charAt(3) - 'a';
if (find(parent, index1) == find(parent, index2)) {
return false;
}
}
}
return true;
}
public void union(int[] parent, int index1, int index2) {
parent[find(parent, index1)] = find(parent, index2);
}
public int find(int[] parent, int index) {
while (parent[index] != index) {
parent[index] = parent[parent[index]];
index = parent[index];
}
return index;
}
}
高手在民间
var equationsPossible = (equations) => {
const uf = new UnionFind(26)
for (const e of equations) {
// 将字母对应成数字
if (e[1] === '=') uf.union(e.charCodeAt(0) - 97, e.charCodeAt(3) - 97)
}
for (const e of equations) {
if (
e[1] == '!' &&
uf.findRoot(e.charCodeAt(0) - 97) == uf.findRoot(e.charCodeAt(3) - 97)
)
return false
}
return true
}
class UnionFind {
constructor(num) {
// num 顶点个数
this.roots = new Array(num)
this.ranks = new Array(num)
for (let i = 0; i < num; i++) {
this.roots[i] = -1
this.ranks[i] = 0
}
}
findRoot(x) {
// 找出顶点x的根节点
let x_root = x
while (this.roots[x_root] !== -1) {
// 一直找父节点,找到尽头
x_root = this.roots[x_root]
}
return x_root // 返回根节点
}
union(x, y) {
// 把顶点x和顶点y所在的集合合并到一起
let x_root = this.findRoot(x)
let y_root = this.findRoot(y)
if (x_root === y_root) return
let x_rank = this.ranks[x_root]
let y_rank = this.ranks[y_root]
if (x_rank < y_rank) {
// 谁高度大,谁就作为根节点
this.roots[x_root] = y_root
} else if (y_rank < x_rank) {
this.roots[y_root] = x_root
} else {
// 一样高,谁作为根节点都行
this.roots[y_root] = x_root
this.ranks[x_root]++
}
}
}
/**
* @param {string[]} equations
* @return {boolean}
*/
var equationsPossible = function (equations) {
let len = equations.length,
parent = [],
cnt = []
for (let i = 0; i < 26; i++) {
parent[i] = i
cnt[i] = 1
}
let find = function (x) {
while (parent[x] != x) {
// 进行路径压缩
parent[x] = parent[parent[x]]
x = parent[x]
}
return x
}
let union = function (a, b) {
let pa = find(a),
pb = find(b)
if (pa == pb) {
return
}
if (cnt[a] > cnt[b]) {
parent[pb] = pa
cnt[b] += cnt[a]
} else {
parent[pa] = pb
cnt[a] += cnt[b]
}
}
for (let i = 0; i < len; i++) {
if (equations[i].indexOf('==') != -1) {
union(
equations[i][0].charCodeAt() - 97,
equations[i][3].charCodeAt() - 97
)
}
}
for (let i = 0; i < len; i++) {
if (equations[i].indexOf('==') == -1) {
let t1 = equations[i][0].charCodeAt() - 97,
t2 = equations[i][3].charCodeAt() - 97
if (find(t1) == find(t2)) {
return false
}
}
}
return true
}
博客: 小书童博客
公号: 坑人的小书童
上一篇: ES6异步方案之Promise详解
下一篇: Promise从入门到精通