Skip to content

Commit a79ba30

Browse files
authored
Create check-for-contradictions-in-equations.py
1 parent 3285596 commit a79ba30

File tree

1 file changed

+105
-0
lines changed

1 file changed

+105
-0
lines changed
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
# Time: O(e + q)
2+
# Space: O(n)
3+
4+
import collections
5+
import itertools
6+
7+
8+
class UnionFind(object):
9+
def __init__(self):
10+
self.set = {}
11+
self.rank = collections.Counter()
12+
13+
def find_set(self, x):
14+
xp, xr = self.set.setdefault(x, (x, 1.0))
15+
if x != xp:
16+
pp, pr = self.find_set(xp) # path compression.
17+
self.set[x] = (pp, xr*pr) # x/pp = xr*pr
18+
return self.set[x]
19+
20+
def union_set(self, x, y, r):
21+
(xp, xr), (yp, yr) = map(self.find_set, (x, y))
22+
if xp == yp:
23+
return False
24+
if self.rank[xp] < self.rank[yp]: # union by rank
25+
# to make x/yp = r*yr and merge xp into yp
26+
# => since x/xp = xr, we can merge with xp/yp = r*yr/xr
27+
self.set[xp] = (yp, r*yr/xr)
28+
elif self.rank[xp] > self.rank[yp]:
29+
# to make y/xp = 1/r*xr and merge xp into yp
30+
# => since y/yp = yr, we can merge with yp/xp = 1/r*xr/yr
31+
self.set[yp] = (xp, 1.0/r*xr/yr)
32+
else:
33+
# to make y/xp = 1/r*xr and merge xp into yp
34+
# => since y/yp = yr, we can merge with yp/xp = 1/r*xr/yr
35+
self.set[yp] = (xp, 1.0/r*xr/yr)
36+
self.rank[xp] += 1
37+
return True
38+
39+
def query_set(self, x, y):
40+
if x not in self.set or y not in self.set:
41+
return -1.0
42+
(xp, xr), (yp, yr) = map(self.find_set, (x, y))
43+
return xr/yr if xp == yp else -1.0
44+
45+
46+
# Time: O(e + q)
47+
# Space: O(n)
48+
import itertools
49+
50+
51+
# union find
52+
class Solution(object):
53+
def checkContradictions(self, equations, values):
54+
"""
55+
:type equations: List[List[str]]
56+
:type values: List[float]
57+
:rtype: bool
58+
"""
59+
EPS = 1e-5
60+
uf = UnionFind()
61+
return any(not uf.union_set(a, b, k) and abs(uf.query_set(a, b)-k) >= EPS for (a, b), k in itertools.izip(equations, values))
62+
63+
64+
# Time: O(e + q)
65+
# Space: O(n)
66+
import collections
67+
import itertools
68+
69+
70+
# dfs
71+
class Solution2(object):
72+
def checkContradictions(self, equations, values):
73+
"""
74+
:type equations: List[List[str]]
75+
:type values: List[float]
76+
:rtype: bool
77+
"""
78+
def isclose(a, b, rel_tol=1e-09, abs_tol=0.0):
79+
return abs(a-b) <= max(rel_tol * max(abs(a), abs(b)), abs_tol)
80+
81+
def iter_dfs(adj, u, lookup):
82+
stk = [u]
83+
lookup[u] = 1.0
84+
while stk:
85+
u = stk.pop()
86+
for v, k in adj[u]:
87+
if v in lookup:
88+
if not isclose(lookup[v], lookup[u]*k):
89+
return True
90+
continue
91+
lookup[v] = lookup[u]*k
92+
stk.append(v)
93+
return False
94+
95+
adj = collections.defaultdict(set)
96+
for (a, b), k in itertools.izip(equations, values):
97+
adj[a].add((b, 1.0/k))
98+
adj[b].add((a, 1.0*k))
99+
lookup = {}
100+
for u in adj.iterkeys():
101+
if u in lookup:
102+
continue
103+
if iter_dfs(adj, u, lookup):
104+
return True
105+
return False

0 commit comments

Comments
 (0)