《Cracking the Coding Interview》——第18章:难题——题目13
2014-04-29 04:40
题目:给定一个字母组成的矩阵,和一个包含一堆单词的词典。请从矩阵中找出一个最大的子矩阵,使得从左到右每一行,从上到下每一列组成的单词都包含在词典中。
解法:O(n^3)级别的时间和空间进行动态规划。这道题目和第17章的最后一题很像,由于这题的时间复杂度实在是高,我动手写了字典树进行加速。如果单纯用哈希表来作为词典,查询效率实际会达到O(n)级别,导致最终的算法复杂度为O(n^4)。用字典树则可以加速到O(n^3),因为对于一个字符串“abcd”,只需要从字典树的根节点出发往下走,就可以一次性判断“a”、“ab”、“abc”、“abcd”是否包含在字典里,而用哈希表无法做到这样的效率。动态规划过程仍然是O(n^4)级别,字典树只是将查单词的过程中进行了加速,从O(n^4)加速到了O(n^3)。空间复杂度为O(n^3),用于标记横向和纵向的每一个子段是否包含在字典里。
代码:
// 18.13 There is a matrix of lower case letters. Given a dictionary of words, you have to find the maximum subrectangle, such that every row reading from left to right, and every column reading from top to bottom is a word in the dictionary. Return the area as the result.
#include <iostream>
#include <string>
#include <unordered_set>
#include <vector>
using namespace std; const int MAX_NODE = ; struct TrieNode {
bool is_word;
char ch;
vector<int> child;
TrieNode(char _ch = ): is_word(false), ch(_ch), child(vector<int>(, -)) {};
};
int node_count;
TrieNode nodes[MAX_NODE]; void insertWordIntoTrie(int root, const string &s)
{
int len = s.length(); for (int i = ; i < len; ++i) {
if (nodes[root].child[s[i] - 'a'] < ) {
nodes[root].child[s[i] - 'a'] = node_count++;
root = nodes[root].child[s[i] - 'a'];
nodes[root].ch = s[i];
} else {
root = nodes[root].child[s[i] - 'a'];
}
if (i == len - ) {
nodes[root].is_word = true;
}
}
} int constructTrie(const unordered_set<string> &dict)
{
int root = node_count++; unordered_set<string>::const_iterator usit;
for (usit = dict.begin(); usit != dict.end(); ++usit) {
insertWordIntoTrie(root, *usit);
} return root;
} int main()
{
int i, j, k;
int i1, i2;
string s;
int n, m;
vector<vector<char> > matrix;
vector<vector<vector<bool> > > is_row_word;
vector<vector<vector<bool> > > is_col_word;
vector<int> dp;
unordered_set<string> dict;
int root;
int ptr;
int max_area; while (cin >> n && n > ) {
node_count = ;
for (i = ; i < n; ++i) {
cin >> s;
dict.insert(s);
}
root = constructTrie(dict); cin >> n >> m; matrix.resize(n);
for (i = ; i < n; ++i) {
matrix[i].resize(m);
}
for (i = ; i < n; ++i) {
cin >> s;
for (j = ; j < m; ++j) {
matrix[i][j] = s[j];
}
} is_row_word.resize(n);
for (i = ; i < n; ++i) {
is_row_word[i].resize(m);
for (j = ; j < m; ++j) {
is_row_word[i][j].resize(m);
}
} is_col_word.resize(m);
for (i = ; i < m; ++i) {
is_col_word[i].resize(n);
for (j = ; j < n; ++j) {
is_col_word[i][j].resize(n);
}
} for (i = ; i < n; ++i) {
for (j = ; j < m; ++j) {
ptr = root;
for (k = j; k < m; ++k) {
if (ptr < ) {
is_row_word[i][j][k] = false;
continue;
} ptr = nodes[ptr].child[matrix[i][k] - 'a'];
if (ptr < ) {
is_row_word[i][j][k] = false;
continue;
} is_row_word[i][j][k] = nodes[ptr].is_word;
}
}
} for (i = ; i < m; ++i) {
for (j = ; j < n; ++j) {
ptr = root;
for (k = j; k < n; ++k) {
if (ptr < ) {
is_col_word[i][j][k] = false;
continue;
} ptr = nodes[ptr].child[matrix[k][i] - 'a'];
if (ptr < ) {
is_col_word[i][j][k] = false;
continue;
} is_col_word[i][j][k] = nodes[ptr].is_word;
}
}
} max_area = ;
dp.resize(m);
for (i1 = ; i1 < n; ++i1) {
for (i2 = i1; i2 < n; ++i2) {
k = ;
for (j = ; j < m; ++j) {
dp[j] = is_col_word[j][i1][i2] ? (++k) : (k = );
if (!dp[j]) {
continue;
} for (i = i1; i <= i2; ++i) {
if (!is_row_word[i][j - dp[j] + ][j]) {
break;
}
}
if (i > i2) {
max_area = max(max_area, (i2 - i1 + ) * dp[j]);
}
}
}
} cout << max_area << endl; // clear up data
dict.clear();
for (i = ; i < n; ++i) {
matrix[i].clear();
}
matrix.clear(); for (i = ; i < n; ++i) {
for (j = ; j < m; ++j) {
is_row_word[i][j].clear();
}
is_row_word[i].clear();
}
is_row_word.clear(); for (i = ; i < m; ++i) {
for (j = ; j < n; ++j) {
is_col_word[i][j].clear();
}
is_col_word[i].clear();
}
is_col_word.clear();
} return ;
}
《Cracking the Coding Interview》——第18章:难题——题目13的更多相关文章
- Cracking the coding interview 第一章问题及解答
Cracking the coding interview 第一章问题及解答 不管是不是要挪地方,面试题具有很好的联系代码总用,参加新工作的半年里,做的大多是探索性的工作,反而代码写得少了,不高兴,最 ...
- 《Cracking the Coding Interview》读书笔记
<Cracking the Coding Interview>是适合硅谷技术面试的一本面试指南,因为题目分类清晰,风格比较靠谱,所以广受推崇. 以下是我的读书笔记,基本都是每章的课后习题解 ...
- Cracking the coding interview
写在开头 最近忙于论文的开题等工作,还有阿里的实习笔试,被虐的还行,说还行是因为自己的水平或者说是自己准备的还没有达到他们所需要人才的水平,所以就想找一本面试的书<Cracking the co ...
- Cracking the coding interview目录及资料收集
前言 <Cracking the coding interview>是一本被许多人极力推荐的程序员面试书籍, 详情可见:http://www.careercup.com/book. 第六版 ...
- Cracking the Coding Interview(Trees and Graphs)
Cracking the Coding Interview(Trees and Graphs) 树和图的训练平时相对很少,还是要加强训练一些树和图的基础算法.自己对树节点的设计应该不是很合理,多多少少 ...
- Cracking the Coding Interview(Stacks and Queues)
Cracking the Coding Interview(Stacks and Queues) 1.Describe how you could use a single array to impl ...
- 二刷Cracking the Coding Interview(CC150第五版)
第18章---高度难题 1,-------另类加法.实现加法. 另类加法 参与人数:327时间限制:3秒空间限制:32768K 算法知识视频讲解 题目描述 请编写一个函数,将两个数字相加.不得使用+或 ...
- 《Cracking the Coding Interview》——第18章:难题——题目12
2014-04-29 04:36 题目:最大子数组和的二位扩展:最大子矩阵和. 解法:一个维度上进行枚举,复杂度O(n^2):另一个维度执行最大子数组和算法,复杂度O(n).总体时间复杂度为O(n^3 ...
- 《Cracking the Coding Interview》——第18章:难题——题目11
2014-04-29 04:30 题目:给定一个由‘0’或者‘1’构成的二维数组,找出一个四条边全部由‘1’构成的正方形(矩形中间可以有‘0’),使得矩形面积最大. 解法:用动态规划思想,记录二维数组 ...
随机推荐
- Ubuntu Deb包安装<个人笔记>
安装 删除 卸载 Deb 包文件 图形界面: 安装deb 直接双击图标,输入密码后就可自动安装. 卸载deb 1. 菜单-系统->系统管理->新立得软件包管理器 或 Alt+F2(运行 ...
- Selenium入门15 截图
截图方法: 1 保存截图 get_screenshot_as_file('保存路径\\文件名.png') #有一个\是转义符 2 保存截图 save_screenshot('保存路径\\文件名 ...
- Map的嵌套,HDU(1263)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1263 新学的map的嵌套 #include <stdio.h> #include < ...
- laravel 去掉index.php伪静态
1,首先,让apache服务器支持rewrite 可以在apache配置文件中定义rewrite规则,是全局的,无论哪个应用都实用 //httpd.config Listen 80 RewriteEn ...
- iPad游戏 Calcculator: The Game 程序自动计算求解方法
今天在iPad上下了个小游戏,主要是一个计算器的界面,有开始值,目标值,限定步数,以及一些加减乘除,还有作者脑洞想出来的功能键,主要有左移,直接把一个数加到末尾,将其中的某个数改为另一个数等等..玩到 ...
- Thymeleaf显示Map集合数据
<select class="form-control zz-set-input-size" id="channel"> <option va ...
- 分享spring、spring boot、spring cloud一些学习资源,从基础知识到项目实战
1.spring注解驱动开发,学习spring boot和spring cloud必备知识 链接: https://pan.baidu.com/s/1xhULzLlpkERhoMi1G5Lgfg 密码 ...
- 使用 python快速搭建http服务
在 Linux 服务器上或安装了 Python 的机器上,Python自带了一个WEB服务器 SimpleHTTPServer. 我们可以很简单的使用 python -m SimpleHTTPSer ...
- Java OOP——第七章 多线程
1.进程:是指运行中的应用程序,每个进程都有自己独立的地址空间(内存空间): Eg:用户点击桌面的IE浏览器,就启动了一个进程,操作系统就会为该进程分配独立的地址空间.当用户再次点击左面的IE浏览器, ...
- 课时16.HTML-XHTML-HTML5区别(了解)
简而言之 HTML语法非常宽松容错性强: XHTML更为严格,它要求标签必须小写,必须严格闭合,标签中的属性必须使用引号引起等等. HTML5是HTML的下一个版本所以除了非常宽松容错性强以外,还增加 ...