Cracking the coding interview--Q20.13

本文介绍了一种算法,用于在百万单词的字典中找出最大可能的字母矩形,使得每行和每列都能组成单词。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目

原文:

Given a dictionary of millions of words, give an algorithm to find the largest possible rectangle of letters such that every row forms a word (reading left to right) and every column forms a word (reading top to bottom).

译文:

 有百万个单词的字典,给一个算法找出最大可能的字母矩形使每行(从左到右)和每列(从上到下)形成一个单词。

解答

ctci解法:

Many problems involving a dictionary can be solved by doing some preprocessing. Where can we do preprocessing?
Well, if we’re going to create a rectangle of words, we know that each row must be the same length and each column must have the same length. So, let’s group the words of the dictionary based on their sizes. Let’s call this grouping D, where D[i] provides a list of words of length i.
Next, observe that we’re looking for the largest rectangle. What is the absolute largest rectangle that could be formed? It’s (length of largest word) * (length of largest word).
 许多问题包含字典可以通过预处理被解决。但如何预处理?
 好的,如果我们将要创建矩形单词,我们知道每行必须同样长度,每列也必须同样长度。所以,让我们基于单词的长度将字典里面的单词分为不同组。我们调用单词组D,在D[i]提供一列长度为i的单词。
 接下来,观察我们找出最长的矩形,绝对值最大的矩形可能就形成了?它是(最大长度的单词)*(最大长度的单词)

	int max_rectangle = longest_word * longest_word;
	for z = max_rectangle to 1 {
		for each pair of numbers (i, j) where i*j = z {
			// attempt to make rectangle. return if successful. 
		}
	}

By iterating in this order, we ensure that the first rectangle we find will be the largest.
Now, for the hard part: make_rectangle. Our approach is to rearrange words in list1 into rows and check if the columns are valid words in list2. However, instead of creating, say, a particular 10x20 rectangle, we check if the columns created after inserting the first two words are even valid pre-fixes. A trie becomes handy here.

通过按照这个顺序遍历,我们保证找到的第一个矩形是最大的;

现在最难的部分:make_rectangle,我们的下一步是按行重新排列在列表1的单词,并检查在列表2的列的单词是否有效。
然后,创建一个特殊的10x20的矩阵,我们再检查是否列已经在前两个单词就被创造,一个单词查找树就很容易得到。

WordGroup[] groupList = WordGroup.createWordGroups(list);
private int maxWordLength = groupList.length;
private Trie trieList[] = new Trie[maxWordLength];

public Rectangle maxRectangle() {
	int maxSize = maxWordLength * maxWordLength;
	for (int z = maxSize; z > 0; z--) {
		for (int i = 1; i <= maxWordLength; i ++ ) {
			if (z % i == 0) {
				int j = z / i;
				if (j <= maxWordLength) {
					Rectangle rectangle = makeRectangle(i,j);
					if (rectangle != null) {
						return rectangle;
					}
				}
			}
		}
	}
	return null;
}
	
private Rectangle makeRectangle(int length, int height) {
	if (groupList[length - 1] == null || groupList[height - 1] == null) {
		return null;
	}
	if (trieList[height - 1] == null) {
		LinkedList<String> words = groupList[height - 1].getWords();
		trieList[height - 1] = new Trie(words);
	}
	return makePartialRectangle(length, height, new Rectangle(length));
}
	
private Rectangle makePartialRectangle(int l, int h, Rectangle rectangle) {
	if (rectangle.height == h) { // Check if complete rectangle
		if (rectangle.isComplete(l, h, groupList[h - 1])) {
			return rectangle;
		} else {
			return null;
		}
	}
	
	// Compare columns to trie to see if potentially valid rect */
	if (!rectangle.isPartialOK(l, trieList[h - 1])) return null;
	
	for (int i = 0; i < groupList[l-1].length(); i++) {
		Rectangle org_plus = rectangle.append(groupList[l-1].getWord(i));
		Rectangle rect = makePartialRectangle(l, h, org_plus);
		if (rect != null) {
			return rect;
		}
	}
	return null;
}

(未完待续)

---EOF---

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值