深度优先搜索
并查集
图
数组
题目描述
给你一个由字符串二维数组 equations
和实数数组 values
,其中 equations[i] = [Ai , Bi ]
,values[i]
表示 Ai / Bi = values[i]
.。
确定方程中是否存在矛盾。如果存在矛盾则返回 true
,否则返回 false
。
注意 :
当检查两个数字是否相等时,检查它们的 绝对差值 是否小于 10-5
.
生成的测试用例没有针对精度的用例,即使用 double
就足以解决问题。
示例 1:
输入: equations = [["a","b"],["b","c"],["a","c"]], values = [3,0.5,1.5]
输出: false
解释:
给定的方程为: a / b = 3, b / c = 0.5, a / c = 1.5
方程中没有矛盾。满足所有方程的一个可能的分配是:
a = 3, b = 1 和 c = 2.
示例 2:
输入: equations = [["le","et"],["le","code"],["code","et"]], values = [2,5,0.5]
输出: true
解释:
给定的方程为: le / et = 2, le / code = 5, code / et = 0.5
根据前两个方程,我们得到 code / et = 0.4.
因为第三个方程是 code / et = 0.5, 所以矛盾。
提示:
1 <= equations.length <= 100
equations[i].length == 2
1 <= Ai .length, Bi .length <= 5
Ai
, Bi
由小写英文字母组成。
equations.length == values.length
0.0 < values[i] <= 10.0
values[i]
小数点后最多 2 位。
解法
方法一:带权并查集
我们先将字符串转换成从 $0$ 开始的整数,然后遍历所有的等式,将等式中的两个字符串映射成对应的整数 $a$ 和 $b$,如果这两个整数不在同一个集合中,就将它们合并到同一个集合中,并且记录下两个整数的权值,即 $a$ 与 $b$ 的比值。如果这两个整数在同一个集合中,就判断它们的权值是否满足等式,如果不满足就返回 true
。
时间复杂度 $O(n \times \log n)$ 或 $O(n \times \alpha(n))$,空间复杂度 $O(n)$。其中 $n$ 是等式的数量。
相似题目:
Python3 Java C++ Go TypeScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 class Solution :
def checkContradictions (
self , equations : List [ List [ str ]], values : List [ float ]
) -> bool :
def find ( x : int ) -> int :
if p [ x ] != x :
root = find ( p [ x ])
w [ x ] *= w [ p [ x ]]
p [ x ] = root
return p [ x ]
d = defaultdict ( int )
n = 0
for e in equations :
for s in e :
if s not in d :
d [ s ] = n
n += 1
p = list ( range ( n ))
w = [ 1.0 ] * n
eps = 1e-5
for ( a , b ), v in zip ( equations , values ):
a , b = d [ a ], d [ b ]
pa , pb = find ( a ), find ( b )
if pa != pb :
p [ pb ] = pa
w [ pb ] = v * w [ a ] / w [ b ]
elif abs ( v * w [ a ] - w [ b ]) >= eps :
return True
return False
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44 class Solution {
private int [] p ;
private double [] w ;
public boolean checkContradictions ( List < List < String >> equations , double [] values ) {
Map < String , Integer > d = new HashMap <> ();
int n = 0 ;
for ( var e : equations ) {
for ( var s : e ) {
if ( ! d . containsKey ( s )) {
d . put ( s , n ++ );
}
}
}
p = new int [ n ] ;
w = new double [ n ] ;
for ( int i = 0 ; i < n ; ++ i ) {
p [ i ] = i ;
w [ i ] = 1.0 ;
}
final double eps = 1e-5 ;
for ( int i = 0 ; i < equations . size (); ++ i ) {
int a = d . get ( equations . get ( i ). get ( 0 )), b = d . get ( equations . get ( i ). get ( 1 ));
int pa = find ( a ), pb = find ( b );
double v = values [ i ] ;
if ( pa != pb ) {
p [ pb ] = pa ;
w [ pb ] = v * w [ a ] / w [ b ] ;
} else if ( Math . abs ( v * w [ a ] - w [ b ] ) >= eps ) {
return true ;
}
}
return false ;
}
private int find ( int x ) {
if ( p [ x ] != x ) {
int root = find ( p [ x ] );
w [ x ] *= w [ p [ x ]] ;
p [ x ] = root ;
}
return p [ x ] ;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37 class Solution {
public :
bool checkContradictions ( vector < vector < string >>& equations , vector < double >& values ) {
unordered_map < string , int > d ;
int n = 0 ;
for ( auto & e : equations ) {
for ( auto & s : e ) {
if ( ! d . count ( s )) {
d [ s ] = n ++ ;
}
}
}
vector < int > p ( n );
iota ( p . begin (), p . end (), 0 );
vector < double > w ( n , 1.0 );
function < int ( int ) > find = [ & ]( int x ) -> int {
if ( p [ x ] != x ) {
int root = find ( p [ x ]);
w [ x ] *= w [ p [ x ]];
p [ x ] = root ;
}
return p [ x ];
};
for ( int i = 0 ; i < equations . size (); ++ i ) {
int a = d [ equations [ i ][ 0 ]], b = d [ equations [ i ][ 1 ]];
double v = values [ i ];
int pa = find ( a ), pb = find ( b );
if ( pa != pb ) {
p [ pb ] = pa ;
w [ pb ] = v * w [ a ] / w [ b ];
} else if ( fabs ( v * w [ a ] - w [ b ]) >= 1e-5 ) {
return true ;
}
}
return false ;
}
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47 func checkContradictions ( equations [][] string , values [] float64 ) bool {
d := make ( map [ string ] int )
n := 0
for _ , e := range equations {
for _ , s := range e {
if _ , ok := d [ s ]; ! ok {
d [ s ] = n
n ++
}
}
}
p := make ([] int , n )
for i := range p {
p [ i ] = i
}
w := make ([] float64 , n )
for i := range w {
w [ i ] = 1.0
}
var find func ( int ) int
find = func ( x int ) int {
if p [ x ] != x {
root := find ( p [ x ])
w [ x ] *= w [ p [ x ]]
p [ x ] = root
}
return p [ x ]
}
for i , e := range equations {
a , b := d [ e [ 0 ]], d [ e [ 1 ]]
v := values [ i ]
pa , pb := find ( a ), find ( b )
if pa != pb {
p [ pb ] = pa
w [ pb ] = v * w [ a ] / w [ b ]
} else if v * w [ a ] - w [ b ] >= 1e-5 || w [ b ] - v * w [ a ] >= 1e-5 {
return true
}
}
return false
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43 function checkContradictions ( equations : string [][], values : number []) : boolean {
const d : { [ key : string ] : number } = {};
let n = 0 ;
for ( const e of equations ) {
for ( const s of e ) {
if ( ! ( s in d )) {
d [ s ] = n ;
n ++ ;
}
}
}
const p : number [] = Array . from ({ length : n }, ( _ , i ) => i );
const w : number [] = Array . from ({ length : n }, () => 1.0 );
const find = ( x : number ) : number => {
if ( p [ x ] !== x ) {
const root = find ( p [ x ]);
w [ x ] *= w [ p [ x ]];
p [ x ] = root ;
}
return p [ x ];
};
for ( let i = 0 ; i < equations . length ; i ++ ) {
const a = d [ equations [ i ][ 0 ]];
const b = d [ equations [ i ][ 1 ]];
const v = values [ i ];
const pa = find ( a );
const pb = find ( b );
if ( pa !== pb ) {
p [ pb ] = pa ;
w [ pb ] = ( v * w [ a ]) / w [ b ];
} else if ( Math . abs ( v * w [ a ] - w [ b ]) >= 1e-5 ) {
return true ;
}
}
return false ;
}
GitHub