并查集-句子相似性

229 阅读2分钟

737. 句子相似性 II

我们可以将一个句子表示为一个单词数组,例如,句子 I am happy with leetcode"可以表示为 arr = ["I","am",happy","with","leetcode"]

给定两个句子 sentence1 和 sentence2 分别表示为一个字符串数组,并给定一个字符串对 similarPairs ,其中 similarPairs[i] = [xi, yi] 表示两个单词 xi 和 yi 是相似的。

如果 sentence1 和 sentence2 相似则返回 true ,如果不相似则返回 false 。

两个句子是相似的,如果:

  • 它们具有 相同的长度 (即相同的字数)
  • sentence1[i] 和 sentence2[i] 是相似的

请注意,一个词总是与它自己相似,也请注意,相似关系是可传递的。例如,如果单词 a 和 b 是相似的,单词 b 和 c 也是相似的,那么 a 和 c 也是 相似 的。

 

示例 1:

输入: sentence1 = ["great","acting","skills"], sentence2 = ["fine","drama","talent"], similarPairs = [["great","good"],["fine","good"],["drama","acting"],["skills","talent"]]
输出: true
解释: 这两个句子长度相同,每个单词都相似。

示例 2:

输入: sentence1 = ["I","love","leetcode"], sentence2 = ["I","love","onepiece"], similarPairs = [["manga","onepiece"],["platform","anime"],["leetcode","platform"],["anime","manga"]]
输出: true
解释: "leetcode" --> "platform" --> "anime" --> "manga" --> "onepiece".
因为“leetcode”和“onepiece”相似,而且前两个单词是相同的,所以这两句话是相似的。

示例 3:

输入: sentence1 = ["I","love","leetcode"], sentence2 = ["I","love","onepiece"], similarPairs = [["manga","hunterXhunter"],["platform","anime"],["leetcode","platform"],["anime","manga"]]
输出: false
解释: “leetcode”和“onepiece”不相似。

 

提示:

  • 1 <= sentence1.length, sentence2.length <= 1000
  • 1 <= sentence1[i].length, sentence2[i].length <= 20
  • sentence1[i] 和 sentence2[i] 只包含大小写英文字母
  • 0 <= similarPairs.length <= 2000
  • similarPairs[i].length == 2
  • 1 <= xi.length, yi.length <= 20
  • xi 和 yi 只含英文字母
/**
 * @param {string[]} sentence1
 * @param {string[]} sentence2
 * @param {string[][]} similarPairs
 * @return {boolean}
 */
var areSentencesSimilarTwo = function(sentence1, sentence2, similarPairs) {
	const sentenceLen1 = sentence1.length;
	const sentenceLen2 = sentence2.length;
	if (sentenceLen1 !== sentenceLen2) {
		return false;
	}
	
	const similarLength = similarPairs.length;
	if (!similarLength) {
		return false;
	}
	const map = new Map();
	for (let i = 0; i < similarLength; i++) {
		for (let j = 0; j < 2; j++) {
			if (!map.has(similarPairs[i][j])) {
				map.set(similarPairs[i][j], map.size);
			}
		}
	}

	const unionFind = new UnionFind(map.size);
	for (let i = 0; i < similarLength; i++) {
		unionFind.union(map.get(similarPairs[i][0]), map.get(similarPairs[i][1]));
	}

	for (let i = 0; i < sentenceLen1; i++) {
		if (!unionFind.checkUnion(map.get(sentence1[i]), map.get(sentence2[i]))) {
			return false;
		}
	}

	return true;
};

class UnionFind {
	constructor(count) {
		this.count = count;
		this.parents = [];
		this.sizes = new Array(count).fill(1);
		this.init();
	}

	init() {
		for (let i = 0; i < this.count; i++) {
			this.parents[i] = i;
		}
	}

	find(node) {
		let curNode = node;
		while (this.parents[curNode] !== curNode) {
			this.parents[curNode] = this.parents[this.parents[curNode]];
			curNode = this.parents[curNode];
		}

		return curNode;
	}

	union(left, right) {
		const leftRoot = this.find(left);
		const rightRoot = this.find(right);
		if (leftRoot !== rightRoot) {
			if (this.sizes[leftRoot] < this.sizes[rightRoot]) {
				this.parents[leftRoot] = rightRoot;
				this.sizes[rightRoot] += this.sizes[leftRoot];
			} else {
				this.parents[rightRoot] = leftRoot;
				this.sizes[leftRoot] += this.sizes[rightRoot];
			}
			this.count--;
			return true;
		}
		return false;
	}

	checkUnion(left, right) {
		return this.find(left) === this.find(right);
	}
}