给定一个仅包含 0 和 1 的二维二进制矩阵,找出只包含 1 的最大矩形,并返回其面积。
输入描述:
输入一个仅包含’0’和’1’的二维字符数组。
第一行输入左大括号{,最后一行输入右大扩号}。
中间每行输入只包含’0’和’1’的字符数组*(字符数组的长度不超过20),字符使用单引号’’,字符之间使用逗号,隔开,字符数组的开始和结束使用大括号{}。
字符数组之间换行,并使用逗号,隔开。(字符数组的个数不超过20)*。
输出描述:
输出只包含字符’1’的最大矩形的面积。
示例1
输入
{
{‘1’,‘0’},
{‘1’,‘0’}
}
输出
2
示例2
输入
{
{‘0’,‘0’},
{‘0’,‘1’}
}
输出
1
分析:
输入呢,就是一个二维的数组s[m][n]
,m<=20,n<=20,。
现在就是要求出一个矩形面积,面积 r = 长*宽;
长 = 行中包含有字符’1’的位置的下标(最大下标-最小下标)值;
宽 = 列中包含有字符’1’位置的下标(最大-最小)值;
注意是只包含字符’1’的矩形面积,所以重新思考:
使用动态规划,我们可以在线性时间内用上一行每个点的 height,left,和 right 计算出下一行每个点的的height,left,和 right 。
伪代码:
//特殊处理
//处理1
int maxArea(数组)
{
遍历数组行:
碰到字符'1',就开始记录行值,直到碰见‘0’停止记录:
遍历数组列(行值为之前记录的行值):
碰到字符'0'就开始记录,直到碰见‘0’停止记录:
计算c*h的面积;
return c*h;
}
定义主函:
定义数组s[20][20];
分配动态空间;
输入数组:输入这里就比较特殊了,不安常规套路来,有一个固定的形式,所以要进行判断。
//处理2
代码:
#include
using namespace std;
int maxArea(char** s, int K, int n)
{
//特殊处理
//处理
int count1=0,count2=0;
int max=0;
for(int j=0;j<n;j++)
{
for(int i=0;i<K;i++)
{
if(s[i][j] == '1')
{
++count1;
for(int x=0;x<count1;x++)
{
for(int y=0;y<n;y++)
{
if(s[x][y] == '1')
{
++count2;
}
else
{
break;
}
}
}
}
int r = count1*count2;
if(r > max)
max = r;
break;
}
}
return max;
}
int main()
{
char **s;
s =(char**)malloc(sizeof(char*)*20);
for(int i=0;i<20;i++)
{
s[i] = (char*)malloc(sizeof(char)*20);
}
for(int i=0;i<20;i++)
{
for(int j=0;j<20;j++)
{
s[i][j] = '0';
}
}
//对于输入比较特殊了
int i=-2, j=0, k=0;
int K=-1;int n;
char ch;
while(cin.get(ch))
{
if(ch=='{')
{
i++;//记录每行的值
j=0;//记录每列的值
k++;//判断是否输入完成,标志位两个大花括号{{}}
K++;//K为最终行值
}
if(ch=='}')
{
n=j;//n为最终列值
k--;
}
if(ch=='1')
{
s[i][j]='1';
j++;
}
if(ch=='0')
{
s[i][j]='0';
j++;
}
if(k==0)//输入完成,跳出
break;
}
int max = maxArea(s, K, n);
cout<<max<<endl;
for(int i=0;i<20;i++)
{
free(s[i]);
}
free(s);
return 0;
}
fatal error: 'windows.h' file not found
,所以我给注释掉了,然后就通过编译了,但在VS下编译仍需加上这个
头文件,可能是OJ后台自动包含了这个库的内容了吧。#include
#include
#include
using namespace std;
/*
* 动态规划
* 时间复杂度O(mn) 空间复杂度O(n)
* m,n为数组行列数
*/
int maxRectangleArea(char** s, int K, int n)
{
int rows = K, cols = n;
if(K==0 || n==0)
return 0;
vector<int> left(cols, 0); // 最左边的1位置 左边界
vector<int> right(cols, cols); // 右边界
vector<int> height(cols, 0);
int maxArea = 0;
for (int i = 0; i < rows; ++i)
{
int curLeft = 0; // 遇到的最右边的0的序号加1
int curRight = cols; // 遇到的最左边的0的序号
for (int j = 0; j < cols; ++j)
{
if(s[i][j] == '1')
height[j] += 1;
else
height[j] = 0;
}
// 更新left
for (int j = 0; j < cols; ++j)
{
if (s[i][j] == '1')
left[j] = max(left[j],curLeft);
else{
left[j] = 0;
curLeft = j+ 1;
}
}
// 更新right
for (int j = cols-1; j >=0 ; --j) {
if (s[i][j] == '1')
right[j] = min(right[j],curRight);
else{
right[j] = cols;
curRight = j;
}
}
// 更新最大面积
for (int j = 0; j < cols; ++j) {
maxArea = max(maxArea, height[j] * (right[j] - left[j]));
}
}
return maxArea;
}
int main()
{
char **s;
s =(char**)malloc(sizeof(char*)*20);
for(int i=0;i<20;i++)
{
s[i] = (char*)malloc(sizeof(char)*20);
}
for(int i=0;i<20;i++)
{
for(int j=0;j<20;j++)
{
s[i][j] = '0';
}
}
//对于输入比较特殊了
int i=-2, j=0, k=0;
int K=-1;int n;
char ch;
while(cin.get(ch))
{
if(ch=='{')
{
i++;//记录每行的值
j=0;//记录每列的值
k++;//判断是否输入完成,标志位两个大花括号{{}}
K++;//K为最终行值
}
if(ch=='}')
{
n=j;//n为最终列值
k--;
}
if(ch=='1')
{
s[i][j]='1';
j++;
}
if(ch=='0')
{
s[i][j]='0';
j++;
}
if(k==0)//输入完成,跳出
break;
}
int maxArea = maxRectangleArea(s, K, n);
cout<<maxArea<<endl;
for(int i=0;i<20;i++)
{
free(s[i]);
}
free(s);
return 0;
}
笔记:
这个题的特殊点就在输入部分,所以没有用纯C++里的vector来进行定义。
为二维数组开辟空间:
char **s;
s =(char**)malloc(sizeof(char*)*20);
for(int i=0;i<20;i++)
{
s[i] = (char*)malloc(sizeof(char)*20);
}
释放二位数组的动态空间:注意顺序不能乱,先释放数组内空间,再释放指针空间!!
for(int i=0;i<20;i++)
{
free(s[i]);
}
free(s);
#include
#include
using namespace std;
int main()
{
//第一种定义方式:定义未知长度的向量
vector<int> vec;
//第二种定义方法,把n个长度的数初始化为0
vector<int> vec(n,0);
//第三种定义方法,是定义一个固定长度的数组
vector<int> vec(100);
//第四种是定义一个二维数组,但是需要手动初始化才能够使用
vector<int> vec[1005];
//第五种也是二维数组的定义方式,是在定义的时候就把数据初始化了
vector<vector<int> > vec(n,vector<int>(n,0));
return 0;
}