LeetCode 990. 等式方程的可知足性 | Python

990. 等式方程的可知足性


題目來源:力扣(LeetCode)https://leetcode-cn.com/problems/satisfiability-of-equality-equationspython

題目


給定一個由表示變量之間關係的字符串方程組成的數組,每一個字符串方程 equations[i] 的長度爲 4,並採用兩種不一樣的形式之一:"a==b" 或 "a!=b"。在這裏,a 和 b 是小寫字母(不必定不一樣),表示單字母變量名。算法

只有當能夠將整數分配給變量名,以便知足全部給定的方程時才返回 true,不然返回 false。數組

示例 1:bash

輸入:["a==b","b!=a"]
輸出:false
解釋:若是咱們指定,a = 1 且 b = 1,那麼能夠知足第一個方程,但沒法知足第二個方程。沒有辦法分配變量同時知足這兩個方程。

示例 2:微信

輸出:["b==a","a==b"]
輸入:true
解釋:咱們能夠指定 a = 1 且 b = 1 以知足知足這兩個方程。

示例 3:spa

輸入:["a==b","b==c","a==c"]
輸出:true

示例 4:設計

輸入:["a==b","b!=c","c==a"]
輸出:false

示例 5:code

輸入:["c==c","b==d","x!=z"]
輸出:true

提示:blog

  • 1 <= equations.length <= 500
  • equations[i].length == 4
  • equationsi 和 equationsi 是小寫字母
  • equationsi 要麼是 '=',要麼是 '!'
  • equationsi 是 '='

解題思路


思路:並查集leetcode

先看例 3 和 例 4。這兩個例題中,所給不一樣部分就是數組中第二個方程式。看看例 4 中,爲什麼返回的結果是 False?

["a==b","b!=c","c==a"]

在例 4 當中,第二個式子 b!=c,而前面的式子中 a==c 那麼這裏將 a 替換 b,第二個式子就變爲 a!=c,可是最後的式子中 a==c 又成立,這裏就明顯存在衝突,因此這裏結果返回 False。

在上面的例子當中,咱們也能夠看到,相等關係具備傳遞性,全部的相等變量實際上是屬於同一個集合。可是這裏並不關心傳遞的距離,只關心是否連通。那麼這裏就考慮使用並查集來解決本問題。

這裏,關於並查集設計算法具體以下:

  • 首先構造並查集,遍歷全部等式。每一個等式的兩個變量屬於連通份量,將二者進行合併;
  • 這裏還須要再次遍歷全部不等式,由於不等式的兩個變量不屬於同一個連通份量,這裏二者不能合併,要分開查找對應的連通份量,這裏有兩種狀況:

    • 若是兩個變量屬於同個連通份量,那麼就與原假設不符,存在矛盾,這裏應該返回 False;
    • 若是沒有出現上面所述的矛盾,那麼最終返回 True

在這裏,咱們能夠將數組中方程式的變量當成節點,相等關係則表示兩個節點的邊。前面說明,相等變量屬於同個連通份量,那麼使用並查集來維護這個關係

具體的實現:

  • 建立數組存儲每一個變量的連通份量,其中每一個元素表示的是所在連通份量的父節點信息。若是父節點是自身,那麼這個就是所在連通份量的根節點。
  • 初始化的時候,將變量的父節點都指向自身。
  • 查找操做:從當前變量的父節點往上找,直至找到根節點;
  • 合併操做:將其中一個變量的根節點指向另一個變量的根節點。

具體的代碼實現以下。

代碼實現


from typing import List
class Solution:

    # 並查集類
    class UnionFind(object):
        def __init__(self):
            '''初始化數組
            '''
            self.parent = list(range(26))
        
        def find(self, index):
            '''查詢操做
            查詢直至根節點
            這裏使用了路徑壓縮
            '''
            # 若是父節點是自身,那麼就是根節點,返回
            while index!=self.parent[index]:
                self.parent[index] = self.parent[self.parent[index]]
                index = self.parent[index]
            return index
        
        def union(self, index1, index2):
            '''合併操做
            將其中一個變量的根節點指向另一個變量的根節點
            '''
            root_index1 = self.find(index1)
            root_index2 = self.find(index2)
            self.parent[root_index1] = root_index2

        def is_connected(self, index1, index2):
            '''判斷是否連通
            '''
            return self.find(index1) == self.find(index2)

    def equationsPossible(self, equations: List[str]) -> bool:
        uf = Solution.UnionFind()

        # 第一次遍歷全部等式,進行合併
        for equation in equations:
            if equation[1] == "=":
                # 這裏將變量字符轉換爲整數
                # ord('a') 返回對應的十進制整數
                index1 = ord(equation[0]) - ord('a')
                index2 = ord(equation[3]) - ord('a')
                uf.union(index1, index2)
        # 再次遍歷全部不等式,查找對應的連通份量
        for equation in equations:
            if equation[1] == '!':
                index1 = ord(equation[0]) - ord('a')
                index2 = ord(equation[3]) - ord('a')
                # 若是兩個變量屬於同個連通份量,那就出現矛盾,返回 False
                if uf.is_connected(index1, index2):
                    return False
        # 最終沒有矛盾,返回 True
        return True


# equations = ["b==a","a==b"]
equations = ["a==b","b!=a"]

solution = Solution()
solution.equationsPossible(equations)

實現結果


實現結果

總結


  • 經過題中示例,咱們知道等式具備傳遞性。可是題中只關心連通性,並不關心傳遞的距離,因此咱們考慮使用並查集的思路來解決問題。
  • 關於並查集的算法設計流程:

    • 首先構造並查集,先遍歷全部的等式,由於兩個變量這裏屬於同一個連通份量,那麼將其進行合併
    • 再次遍歷 全部的不等式,在這裏兩個變量並不屬於同個連通份量,那麼不能進行合併,要各自查找對應的連通份量。若是這個時候出現兩個變量的連通份量相同的狀況,那麼這個就跟前面的預設不符,出現矛盾。返回 False
    • 若是沒有出現上面所述的矛盾,那麼返回 True。

以上就是關於解決《990. 等式方程的可知足性》問題的主要內容。若是以爲寫得還不錯,歡迎關注。微信公衆號《書所集錄》同步更新,一樣歡迎關注。
相關文章
相關標籤/搜索