题目描述
给你一个边长为 a 的六边形 01 矩阵,请找到一个最大的全1子三角形,输出三角形的边长b。
方法一:动态规划方法
求解思路
对于本题目要求解最大的全1子三角形,因为题目给出的数据,为了方便题目的求解,我们将一维数组表示的六边形矩阵装入二维矩阵。根据边长为a的六边形矩阵,共有2a行,最长4a-1列。我们将其元素放在矩形矩阵的[a-i-1,3a+i-1]中,并且我们根据正六边形的对称性,我们选定其一个朝向,并且用dp[i][j]记录以矩形矩阵中某一个点为顶点的三角形边长的最大值。根据图形的特点我们有状态转移方程:dp[i][j]=min{dp[i+1][j-1],dp[i+1][j+1]}+1.最后根据上述的思路即可得到本题的答案。
解题代码
class Solution {
public:
int largestSubTriangle(int a, vector<int>& maps) {
int n = 4 * a - 1;
vector<vector<int> > matrix(2 * a, vector<int>(n, 0)); // 覆盖六边形的矩阵
vector<vector<int> > tri(2 * a, vector<int>(n, 0)); // 三角形方向
vector<vector<int> > dp(2 * a, vector<int>(n, 0));
int hycount = 0;
int hyres = 0;
for(int i = 0, k = 1; i < a; i++)
{ //遍历上半矩阵
for(int j = a - i - 1; j < 3 * a + i; j++)
{
matrix[i][j] = maps[hycount++];
tri[i][j] = k % 2; // 上半个六边形每行奇数朝上
k++;
}
k = 1;
}
for(int i = a - 1, k = 0; i >= 0; i--)
{ //遍历下半矩阵
for(int j = a - 1 - i; j < 3 * a + i; j++)
{
matrix[2 * a - i - 1][j] = maps[hycount++];
tri[2 * a - i - 1][j] = k % 2; // 下半个六边形每行偶数朝上
k++;
}
k = 0;
}
for(int i = 2 * a - 1; i >= 0; i--)
{ //找朝上的最大三角形
for(int j = n - 1; j >= 0; j--)
{
if(matrix[i][j] == 1)
{
dp[i][j] = 1;
if(i < 2 * a - 1 && j < n - 1 && j > 0 && tri[i][j] == 1 && dp[i + 1][j] == 1)
dp[i][j] = min(dp[i + 1][j - 1], dp[i + 1][j + 1]) + 1;
hyres = max(hyres, dp[i][j]); // 维护最大值
}
}
}
for(int i = 0; i < 2 * a; i++)
{ //找朝下的最大三角形
for(int j = 0; j < n; j++)
{
if(matrix[i][j] == 1)
{
dp[i][j] = 1;
//除去最上一行、最左右两边、朝向向上、上方一个不为1,这四种情况不能为顶部三角,继续添加
if(i > 0 && j < n - 1 && j > 0 && tri[i][j] == 0 && dp[i - 1][j] == 1)
dp[i][j] = min(dp[i - 1][j - 1], dp[i - 1][j + 1]) + 1;
hyres = max(hyres, dp[i][j]); // 更新最大值
}
}
}
return hyres; // 返回结果
}
};复杂度分析
时间复杂度:遍历矩形矩阵,两层循环,因此时间复杂度为(
)
空间复杂度:引入辅助二维数组,因此空间复杂度为(
)
方法二:基于动态规划的优化方法
求解思路
对于方法一,我们考虑在不引入多余的二维数组的情况下对问题进行求解。对于矩形矩阵,我们对于上半矩阵的第i行,那么该行六边形共有2*(a+i)+1个元素,同理下半行也是如此。因此我们设置一个index直接访问数组,不用像方法一中使用二维矩阵来存储。综上,其余根据方法一的做法,即可求得本题的答案。
解题代码
class Solution {
public:
//
int largestSubUpperTriangle(int a, vector<int> &maps)
{ //找到最大的朝下的三角形
int index = 0; // 引入index对本题的解法进行优化
int hyres = 0; // 记录结果
for (int i = 0; i < a; i++)
{ //遍历上半个六边形
int n = 2 * (a + i) + 1; // 该行长度
for (int j = 0; j < n; j++)
{
if (j % 2 == 1)
{ //只找朝下的小三角形
if (j > 1 && j < n - 2 && i != 0) // 不在边界
maps[index] = (maps[index] && maps[index - n + 1] ? 1 + min(maps[index - n + 2], maps[index - n]) : maps[index]);
hyres = max(hyres, maps[index]);
}
index++;
}
}
for (int i = a - 1; i >= 0; i--)
{ //遍历下半个六边形
int n = 2 * (a + i) + 1; // 该行长度
for (int j = 0; j < n; j++)
{
if (j % 2 == 0)
{ //只找朝下的小三角形
if (i == a - 1)
{ //两种情况,与方法一这里对应下半个矩阵从a-1开始
if (j > 0 && j < n - 1) // 不在边界
maps[index] = (maps[index] && maps[index - n] ? 1 + min(maps[index - n - 1], maps[index - n + 1]) : maps[index]);
}
else
{
maps[index] = (maps[index] && maps[index - n - 1] ? 1 + min(maps[index - n - 2], maps[index - n]) : maps[index]);
}
hyres = max(hyres, maps[index]);
}
index++;
}
}
return hyres;
}
int largestSubTriangle(int a, vector<int>& maps) {
int hyres = 0; // 存储结果
hyres = max(hyres, largestSubUpperTriangle(a, maps)); // 朝下的三角形
reverse(maps.begin(), maps.end()); // 逆转数据
hyres = max(hyres, largestSubUpperTriangle(a, maps)); // 朝上的三角形
return hyres; // 返回结果
}
};复杂度分析
时间复杂度:两层循环,因此时间复杂度为
空间复杂度:没有引入额外的内存地址空间,因此空间复杂度为

京公网安备 11010502036488号