[LeetCode] 990. Satisfiability of Equality Equations 等式方程的可滿足性



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. 1 <= equations.length <= 500
  2. equations[i].length == 4
  3. equations[i][0] and equations[i][3] are lowercase letters
  4. equations[i][1] is either '=' or '!'
  5. equations[i][2] is '='

這道題給了一系列簡單的公式,某兩個字母相等或者不等,然后問給的這些公式會不會產生矛盾,就比如說一個是 a==b,另一個是 a!=b,這就是矛盾了。或者有些更復雜的,相等是可以傳遞的,比如例子4中,就是一種比較復雜的情況。這里比較直接的一種解法就是建立無向圖來做,每個字母都可以當作一個結點,然后等號就表示相連的結點。開始時先跳過所有的不等式,通過所有的等式將這個圖建立起來。然后再遍歷所有的不等式,看這兩個結點在圖中是否相連,這里通過遞歸來檢查兩個結點是否相連,常規寫法,注意要使用一個 HashSet 來標記已經訪問過的結點,以免陷入死循環,參見代碼如下:


解法一:

class Solution {
public:
    bool equationsPossible(vector<string>& equations) {
		unordered_map<char, unordered_set<char>> g;
		for (auto eq : equations) {
			if (eq[1] == '!') continue;
			g[eq[0]].insert(eq[3]);
			g[eq[3]].insert(eq[0]);
		}
		for (auto eq : equations) {
			if (eq[1] == '=') continue;
			unordered_set<char> visited;
			if (!check(g, eq[0], eq[3], visited)) return false;
		}
		return true;
    }
	bool check(unordered_map<char, unordered_set<char>>& g, char cur, char target, unordered_set<char>& visited) {
		if (cur == target || g[cur].count(target)) return false;
		for (char c : g[cur]) {
			if (visited.count(c)) continue;
			visited.insert(c);
			if (!check(g, c, target, visited)) return false;
		}
		return true;
	}
};

這道題給的提示使用聯合查找/並查集 Union Find,論壇上的高分解法也是清一色的 UF 做法。核心思想是初始時給每一個對象都賦上不同的標簽,然后對於所有的等式,可以看作是屬於同一個群組的對象,需要在 root 數組中標記一下,標記方法是兩個對象分別調用 find 函數來找出祖先標簽值,然后在 root 數組中再將這兩個值連接起來。接下來遍歷所有不等式,對不等號兩端的對象分別調用 find 函數來找出祖先標簽值,若相等了,則產生了矛盾了,因為這兩個對象 suppose 不能屬於同一個群組的,直接返回 false,參見代碼如下:


解法二:

class Solution {
public:
    bool equationsPossible(vector<string>& equations) {
        vector<int> root(26);
        for (int i = 0; i < 26; ++i) root[i] = i;
        for (string eq : equations) {
            if (eq[1] == '!') continue;
            root[find(root, eq[0] - 'a')] = find(root, eq[3] - 'a');
        }
        for (string eq : equations) {
            if (eq[1] == '=') continue;
            if (find(root, eq[0] - 'a') == find(root, eq[3] - 'a')) return false;
        }
        return true;
    }
    int find(vector<int>& root, int x) {
        return root[x] == x ? x : find(root, root[x]);
    }
};

討論:find 函數的寫法其實有很多種,有遞歸形式,也有迭代形式的,可以參見博主之前的博客 Redundant Connection II


Github 同步地址:

https://github.com/grandyang/leetcode/issues/990


類似題目:

Redundant Connection II

Friend Circles

Graph Valid Tree


參考資料:

https://leetcode.com/problems/satisfiability-of-equality-equations/

https://leetcode.com/problems/satisfiability-of-equality-equations/discuss/234474/C%2B%2B-7-lines-with-picture-union-find

https://leetcode.com/problems/satisfiability-of-equality-equations/discuss/234486/JavaC%2B%2BPython-Easy-Union-Find


LeetCode All in One 題目講解匯總(持續更新中...)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM