持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第13天,点击查看活动详情
79. 单词搜索
思路
(回溯) O(n^2 3^k)
深度优先搜索,我们定义这样一种搜索顺序,即先枚举单词的起点,然后依次枚举单词的每个字母。在这个过程中需要将已经使用过的字母改成一个特殊字母,以避免重复使用字符。
递归函数设计:
bool dfs(vector<vector<char>>& board, string& word,int u,int x,int y)
u代表当前枚举到了目标单词word第u个位置。
x,y是当前搜索到的二维字符网格的横纵坐标。
搜索过程如下:
- 1、在二维字符网格中枚举每个单词的起点。
- 2、从该起点出发向四周搜索单词
word,并记录此时枚举到单词word的第u个位置 (u从0开始)。 - 3、如果当前搜索的位置
(x,y)的元素board[x][y] == word[u],则继续向四周搜索。 - 4、直到枚举到单词
word的最后一个字母返回ture,否则返回false。
递归边界:
- 1、当搜索过程出现当前位置
board[x][y] != word[u],说明当前路径不合法,返回false。 - 2、
u == word.size() - 1,成功搜索到单词末尾,返回true。
实现细节:
-
1、搜索过的位置继续搜索下一层时,需要对当前位置进行标识,表示已经搜索
-
2、可以使用偏移数组来简化代码。
时间复杂度分析: 单词起点一共有 n^2 个,单词的每个字母一共有上下左右四个方向可以选择,但由于不能走回头路,所以除了单词首字母外,仅有三种选择。所以总时间复杂度是 O(n^2 3^k) 。
c++代码
class Solution {
public:
bool exist(vector<vector<char>>& board, string word) {
for(int i = 0; i < board.size(); i++)
for(int j = 0; j < board[i].size(); j++)
if(dfs(board, word, 0, i, j))
return true;
return false;
}
int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1};
bool dfs(vector<vector<char>>& board, string word, int u, int x, int y){
if(board[x][y] != word[u]) return false;
if(u == word.size() - 1){
return true;
}
char t = board[x][y];
board[x][y] = '.';
for(int i = 0; i < 4; i++){
int a = x + dx[i], b = y + dy[i];
if(a < 0 || a >= board.size() || b <0 || b >= board[0].size() || board[a][b] == '.') continue;
if(dfs(board, word, u + 1, a, b))
return true;
}
board[x][y] = t;
return false;
}
};
84. 柱状图中最大的矩形
思路
(单调栈)
对于每个柱子i,找到左边第一个比它小的柱子的位置left[i],和找到右边第一个比它小的柱子的位置right[i],(right[i] - left[i] - 1) * heights[i]是当前柱子所能找到的最大的矩形面积。
c++代码
class Solution {
public:
int largestRectangleArea(vector<int>& h) {
int n = h.size();
vector<int> left(n), right(n);
stack<int> st; //单调递增栈
// 寻找左边第一个小于h[i]的数的下标
for(int i = 0; i < n; i++){
while(!st.empty() && h[st.top()] >= h[i]) st.pop(); //维护单调递增栈
if(st.empty()) left[i] = -1;
else left[i] = st.top();
st.push(i);
}
st = stack<int>();
// 寻找右边第一个小于h[i]的数的下标
for(int i = n - 1; i >= 0; i--){
while(!st.empty() && h[st.top()] >= h[i]) st.pop(); //维护单调递增栈
if(st.empty()) right[i] = n;
else right[i] = st.top();
st.push(i);
}
int res = 0;
for(int i = 0; i < n; i++){
res = max(res, (right[i] - left[i] - 1) * h[i]);
}
return res;
}
};
85. 最大矩形
思路
(单调栈) O(n^2)
我们可以枚举每一行,将每一行看成一条基准线。对于某一行,看每个格子向上最多能到达的位置,当做这个位置的高度,然后就转化成了Lc84的问题,如下图是转化过程(当枚举到第6行时,对应的各个柱子,红色的为对应的柱子):
枚举每一行都会得到一个最大矩形的结果,这些结果中最大的一个就是答案。
我们如何得到各个柱子的高度?
动态规划
状态表示: h[i][j]表示以(i, j)为起点对应柱子的最大高度。
状态计算: 如果matrix[i][j] == 1的话,则h[i][j] = h[i - 1][j] + 1,否则h[i][j] = 0。
c++代码
class Solution {
public:
int maxRectangleh(vector<int> h){
int n = h.size();
vector<int> left(n), right(n);
stack<int> stk;
for(int i = 0; i < n; i++){
while(!stk.empty() && h[stk.top()] >= h[i]) stk.pop(); // 单调递增栈
if(stk.empty()) left[i] = -1;
else left[i] = stk.top(); // 左边第一个比h[i]小的位置
stk.push(i);
}
stk = stack<int>(); //栈清空
for(int i = n - 1; i >= 0; i--){
while(!stk.empty() && h[stk.top()] >= h[i]) stk.pop();
if(stk.empty()) right[i] = n;
else right[i] = stk.top(); // 右边第一个比h[i]小的位置
stk.push(i);
}
int res = 0;
for(int i = 0; i < n; i++) res = max(res, h[i] * (right[i] - left[i] - 1));
return res;
}
int maximalRectangle(vector<vector<char>>& matrix) {
int n = matrix.size(),m = matrix[0].size();
if(!n || !m) return 0;
vector<vector<int>>h(n + 1, vector<int>(m + 1));
for(int i = 0; i < n; i++)
for(int j = 0; j < m; j++)
if(matrix[i][j] == '1'){
if(i) h[i][j] = h[i - 1][j] + 1;
else h[i][j] = 1;
}
int res = 0;
for(int i = 0; i < n; i++) res = max(res, maxRectangleh(h[i]));
return res;
}
};