[Swift]LeetCode990. 等式方程的可满足性 | Satisfiability of Equality Equations
★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★
➤微信公众号:山青咏芝(shanqingyongzhi)
➤博客园地址:山青咏芝(https://www.cnblogs.com/strengthen/)
➤GitHub地址:https://github.com/strengthen/LeetCode
➤原文地址:https://www.cnblogs.com/strengthen/p/10361525.html
➤如果链接不是山青咏芝的博客园地址,则可能是爬取作者的文章。
➤原文已修改更新!强烈建议点击原文地址阅读!支持作者!支持原创!
★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★
Given an array equations of strings that represent relationships between variables, each string equations[i]
has length 4
and takes one of two different forms: "a==b"
or "a!=b"
. Here, a
and b
are lowercase letters (not necessarily different) that represent one-letter variable names.
Return true
if and only if it is possible to assign integers to variable names so as to satisfy all the given equations.
Example 1:
Input: ["a==b","b!=a"]
Output: false
Explanation: If we assign say, a = 1 and b = 1, then the first equation is satisfied, but not the second. There is no way to assign the variables to satisfy both equations.
Example 2:
Input: ["b==a","a==b"]
Output: true
Explanation: We could assign a = 1 and b = 1 to satisfy both equations.
Example 3:
Input: ["a==b","b==c","a==c"]
Output: true
Example 4:
Input: ["a==b","b!=c","c==a"]
Output: false
Example 5:
Input: ["c==c","b==d","x!=z"]
Output: true
Note:
1 <= equations.length <= 500
equations[i].length == 4
equations[i][0]
andequations[i][3]
are lowercase lettersequations[i][1]
is either'='
or'!'
equations[i][2]
is'='
给定一个由表示变量之间关系的字符串方程组成的数组,每个字符串方程 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]
是'='
Runtime: 48 ms
Memory Usage: 4 MB
1 class Solution { 2 func equationsPossible(_ equations: [String]) -> Bool { 3 var ds:DJSet = DJSet(26) 4 for e in equations 5 { 6 if e[1] == "=" 7 { 8 var l:Int = e[0].ascii - 97 9 var r:Int = e[3].ascii - 97 10 ds.union(l,r) 11 } 12 } 13 for e in equations 14 { 15 if e[1] == "!" 16 { 17 var l:Int = e[0].ascii - 97 18 var r:Int = e[3].ascii - 97 19 if ds.equiv(l,r) 20 { 21 return false 22 } 23 } 24 } 25 return true 26 } 27 } 28 29 extension String { 30 //subscript函数可以检索数组中的值 31 //直接按照索引方式截取指定索引的字符 32 subscript (_ i: Int) -> Character { 33 //读取字符 34 get {return self[index(startIndex, offsetBy: i)]} 35 } 36 } 37 38 extension Character 39 { 40 //属性:ASCII整数值(定义小写为整数值) 41 var ascii: Int { 42 get { 43 let s = String(self).unicodeScalars 44 return Int(s[s.startIndex].value) 45 } 46 } 47 } 48 49 public class DJSet 50 { 51 var upper:[Int] 52 53 init(_ n:Int) 54 { 55 upper = [Int](repeating:-1,count:n) 56 } 57 58 func root(_ x:Int) -> Int 59 { 60 if(upper[x] < 0) 61 { 62 return x 63 } 64 else 65 { 66 upper[x] = root(upper[x]) 67 return upper[x] 68 } 69 } 70 71 func equiv(_ x:Int,_ y:Int) -> Bool 72 { 73 return root(x) == root(y) 74 } 75 76 func union(_ x:Int,_ y:Int) -> Bool 77 { 78 var x:Int = root(x) 79 var y:Int = root(y) 80 if x != y 81 { 82 if upper[y] < upper[x] 83 { 84 var d:Int = x 85 x = y 86 y = d 87 } 88 upper[x] += upper[y] 89 upper[y] = x 90 } 91 return x == y 92 } 93 94 func count() -> Int 95 { 96 var ct:Int = 0 97 for u in upper 98 { 99 if u < 0 100 { 101 ct += 1 102 } 103 } 104 return ct 105 } 106 }
52ms
1 class Solution { 2 3 typealias Equation = (var1: Character, var2: Character, areEqual: Bool) 4 5 func equationsPossible(_ equations: [String]) -> Bool { 6 var equalHashMap = [Character: Character]() 7 8 let equations = parseEquations(equations) 9 10 // process equality conditions using union-finding algorithm 11 // process inequality conditions 12 13 let equalityEquations = equations.filter { $0.areEqual } 14 let inEqualityEquations = equations.filter { !$0.areEqual } 15 16 // similar union finding algorithm 17 for equation in equalityEquations { 18 let var1 = equation.var1 19 let var2 = equation.var2 20 if equalHashMap[var1] == nil && equalHashMap[var2] == nil { 21 equalHashMap[var1] = var1 22 equalHashMap[var2] = var1 23 } else if equalHashMap[var1] == nil { 24 equalHashMap[var1] = findParent(var2, equalHashMap) 25 } else { // equalHashMap[var2] == nil 26 equalHashMap[var2] = findParent(var1, equalHashMap) 27 } 28 } 29 30 for equation in inEqualityEquations { 31 let var1 = equation.var1 32 let var2 = equation.var2 33 let parentVar1 = equalHashMap[var1] ?? var1 34 let parentVar2 = equalHashMap[var2] ?? var2 35 if parentVar1 == parentVar2 { 36 return false 37 } 38 } 39 40 return true 41 } 42 43 func findParent(_ ch: Character, _ hashMap: [Character: Character]) -> Character { 44 var result = hashMap[ch] ?? ch 45 while let parent = hashMap[result], parent != result { 46 result = parent 47 } 48 return result 49 } 50 51 func parseEquations(_ equations: [String]) -> [Equation] { 52 return equations.map { parseString($0) } 53 } 54 55 func parseString(_ string: String) -> Equation { 56 guard string.count == 4 else { 57 assertionFailure("input string: \(string) not in correct format") 58 return ("a", "a", false) 59 } 60 61 let var1 = string[0] 62 let areEqual = string.subString(from: 1, to: 2) == "==" ? true : false 63 let var2 = string[3] 64 return (var1, var2, areEqual) 65 } 66 67 } 68 69 extension String { 70 71 subscript(i: Int) -> Character { 72 get { 73 return self[index(startIndex, offsetBy: i)] 74 } 75 } 76 77 func subString(from: Int, to: Int) -> String { 78 guard from <= to else { 79 return "" 80 } 81 82 let startIndex = self.index(self.startIndex, offsetBy: from) 83 let endIndex = self.index(self.startIndex, offsetBy: to) 84 return String(self[startIndex...endIndex]) 85 } 86 87 func subString(from: Int) -> String { 88 let startIndex = self.index(self.startIndex, offsetBy: from) 89 return String(self.suffix(from: startIndex)) 90 } 91 92 func asciiValues() -> [Int] { 93 return Array(self.utf16).map { Int($0) } 94 } 95 96 mutating func lTrim(_ regex: String = "^\\s+") { 97 if let trailingSpacesRange = self.range(of: regex, options: .regularExpression) { 98 self.replaceSubrange(trailingSpacesRange, with: "") 99 } 100 } 101 102 mutating func rTrim(_ regex: String = "\\s+$") { 103 if let trailingSpacesRange = self.range(of: regex, options: .regularExpression) { 104 self.replaceSubrange(trailingSpacesRange, with: "") 105 } 106 } 107 108 func stringByReplacingAt(_ index: Int, with ch: Character) -> String { 109 var chars = Array(self) 110 chars[index] = ch 111 let modifiedString = String(chars) 112 return modifiedString 113 } 114 }
56ms
1 class Solution { 2 func equationsPossible(_ equations: [String]) -> Bool { 3 let unionFind = UnionFind.init(26) 4 let equalUnion = equations.filter { $0[1] == "=" } 5 let notEqualUnion = equations.filter { $0[1] == "!" } 6 let startingValue = Character("a").ascii! 7 for item in equalUnion { 8 let left = Int(item[0].ascii! - startingValue) 9 let right = Int(item[3].ascii! - startingValue) 10 unionFind.union(left, right) 11 } 12 13 for item in notEqualUnion { 14 let left = Int(item[0].ascii! - startingValue) 15 let right = Int(item[3].ascii! - startingValue) 16 if unionFind.find(left) == unionFind.find(right) { 17 return false 18 } 19 } 20 return true 21 } 22 } 23 24 extension String { 25 subscript (i: Int) -> Character { 26 return self[index(startIndex, offsetBy: i)] 27 } 28 } 29 30 extension Character { 31 var isAscii: Bool { 32 return unicodeScalars.first?.isASCII == true 33 } 34 var ascii: UInt32? { 35 return isAscii ? unicodeScalars.first?.value : nil 36 } 37 } 38 39 class UnionFind { 40 var root = [Int]() 41 var rank = [Int]() 42 43 public init(_ n: Int) { 44 // if root is not initialized, 'self' captured by a closure before all members were initialized 45 (0...n-1).forEach { root.append($0) } 46 rank = [Int](repeating: 1, count: n) 47 } 48 49 fileprivate func find(_ current: Int) -> Int { 50 var path = [Int]() 51 var current = current 52 while root[current] != current { 53 path.append(current) 54 current = root[current] 55 } 56 57 for p in path { 58 root[p] = current 59 } 60 return current 61 } 62 63 public func union(_ x: Int, _ y: Int) { 64 let xRoot = find(x) 65 let yRoot = find(y) 66 67 if xRoot == yRoot { 68 return 69 } 70 if rank[xRoot] > rank[yRoot] { 71 root[yRoot] = xRoot 72 } else if rank[xRoot] < rank[yRoot] { 73 root[xRoot] = yRoot 74 } else { 75 rank[xRoot] = root[xRoot] + 1 76 root[xRoot] = yRoot 77 } 78 } 79 }
64ms
1 class Solution { 2 func equationsPossible(_ equations: [String]) -> Bool { 3 var dict: [Character: Set<Character>] = [:] 4 var val = 0 5 6 var res = true 7 8 for equation in equations { 9 var equation = equation 10 11 let charA = equation.removeFirst() 12 let sym = equation.removeFirst() 13 if sym != "=" {continue} 14 15 equation.removeFirst() 16 let charB = equation.removeFirst() 17 18 if dict[charA] == nil { 19 dict[charA] = [charA] 20 } 21 22 if dict[charB] == nil { 23 dict[charB] = [charB] 24 } 25 26 let unionSet = (dict[charA]!).union(dict[charB]!) 27 28 for (char, _) in dict where unionSet.contains(char) { 29 dict[char] = unionSet 30 } 31 } 32 33 for equation in equations { 34 var equation = equation 35 36 let charA = equation.removeFirst() 37 let sym = equation.removeFirst() 38 if sym != "!" {continue} 39 40 equation.removeFirst() 41 let charB = equation.removeFirst() 42 43 if charA == charB || (dict[charA] != nil && dict[charB] != nil && dict[charA] == dict[charB] ) { 44 res = false 45 break 46 } 47 } 48 49 return res 50 } 51 }
76ms
1 class Solution { 2 func equationsPossible(_ equations: [String]) -> Bool { 3 let unionFind = UnionFind.init(26) 4 let startingValue = Character("a").ascii! 5 for item in equations { 6 if item[1] == "=" { 7 let left = Int(item.ascii[0] - startingValue) 8 let right = Int(item.ascii[3] - startingValue) 9 unionFind.union(left, right) 10 } 11 } 12 13 for item in equations { 14 if item[1] == "!" { 15 let left = Int(item.ascii[0] - startingValue) 16 let right = Int(item.ascii[3] - startingValue) 17 if unionFind.find(left) == unionFind.find(right) { 18 return false 19 } 20 } 21 } 22 return true 23 } 24 } 25 26 public extension String { 27 subscript (i: Int) -> Character { 28 return self[index(startIndex, offsetBy: i)] 29 } 30 } 31 32 public extension StringProtocol { 33 var ascii: [UInt32] { 34 return compactMap { $0.ascii } 35 } 36 } 37 38 extension Character { 39 var isAscii: Bool { 40 return unicodeScalars.first?.isASCII == true 41 } 42 var ascii: UInt32? { 43 return isAscii ? unicodeScalars.first?.value : nil 44 } 45 } 46 47 class UnionFind { 48 var root = [Int]() 49 var rank = [Int]() 50 51 public init(_ n: Int) { 52 // if root is not initialized, 'self' captured by a closure before all members were initialized 53 (0...n-1).forEach { root.append($0) } 54 rank = [Int](repeating: 1, count: n) 55 } 56 57 fileprivate func find(_ current: Int) -> Int { 58 var path = [Int]() 59 var current = current 60 while root[current] != current { 61 path.append(current) 62 current = root[current] 63 } 64 65 for p in path { 66 root[p] = current 67 } 68 return current 69 } 70 71 public func union(_ x: Int, _ y: Int) { 72 let xRoot = find(x) 73 let yRoot = find(y) 74 75 if xRoot == yRoot { 76 return 77 } 78 if rank[xRoot] > rank[yRoot] { 79 root[yRoot] = xRoot 80 } else if rank[xRoot] < rank[yRoot] { 81 root[xRoot] = yRoot 82 } else { 83 rank[xRoot] = root[xRoot] + 1 84 root[xRoot] = yRoot 85 } 86 } 87 }