腾讯面试题(九度)——面积最大的全1子矩阵

题目地址:http://ac.jobdu.com/problem.php?pid=1497

题目描述:

在一个M * N的矩阵中,所有的元素只有0和1,从这个矩阵中找出一个面积最大的全1子矩阵,所谓最大是指元素1的个数最多。

输入:

输入可能包含多个测试样例。
对于每个测试案例,输入的第一行是两个整数m、n(1<=m、n<=1000):代表将要输入的矩阵的大小。
矩阵共有m行,每行有n个整数,分别是0或1,相邻两数之间严格用一个空格隔开。

输出:

对应每个测试案例,输出矩阵中面积最大的全1子矩阵的元素个数。

样例输入:
2 2
0 0
0 0
4 4
0 0 0 0
0 1 1 0
0 1 1 0
0 0 0 0
样例输出:
0
4

解决方法:

1. 动态规划——三个状态数组,分别保存当前点的高度up,左边界left,右边界right,max_value=max(max_value,up*(right-left+1);

#include <iostream>
using namespace std;
#include <algorithm>

#define N 1000

bool data[N][N];
int up[N][N];
int l_flag[N][N];
int r_flag[N][N];

int main()
{
    int m,n;
    int max_1;
    int l_num,r_num;
    while(cin>>m>>n)
    {
        for(int i=0;i<m;i++)
            for(int j=0;j<n;j++)
                cin>>data[i][j];
        max_1=0;
        for(int i=0;i<m;i++)
        {
            l_num=-1;
            r_num=n;
            for(int j=0;j<n;j++)
            {
                if(!data[i][j])
                {
                    up[i][j]=0;
                    l_flag[i][j]=0;
                    l_num=j;
                }
                else
                {
                    if(i==0)
                    {
                        up[i][j]=1;
                        l_flag[i][j]=l_num+1;
                    }
                    else
                    {
                        up[i][j]=up[i-1][j]+1;
                        l_flag[i][j]=max(l_num+1,l_flag[i-1][j]);
                    }
                }
            }
            for(int j=n-1;j>=0;j--)
            {
                if(!data[i][j])
                {
                    r_flag[i][j]=n;
                    r_num=j;
                }
                else
                {
                    if(i==0)
                        r_flag[i][j]=r_num-1;
                    else
                        r_flag[i][j]=min(r_num-1,r_flag[i-1][j]);
                }
                max_1=max(max_1,up[i][j]*(r_flag[i][j]-l_flag[i][j]+1));
            }
        }
        cout<<max_1<<endl;
    }
    return 0;
}

2.向右得到每个点左边连续1的个数,如 0 1 0 1 1 0 -> 0 1 0 1 2 0。然后算每列的最大1矩阵,例如:

某列 为 1 2 3 3 4 2 0 ,得到最大1矩阵为2*5=10,具体方法为对每个元素分别向上(左)向下(右)查询连续大于等于自己的元素个数,然后相乘

此方法在九都测试超时,但是结果是对的。

#include <iostream>
using namespace std;
#include <algorithm>

bool data[1000][1000];
int flag[1000][1000];

int main()
{
    int m,n;
    int max_1,value,depth;
    int x;
    while(cin>>m>>n)
    {
        for(int i=0;i<m;i++)
            for(int j=0;j<n;j++)
            {
                cin>>data[i][j];
                if(data[i][j])
                {
                    if(j==0)
                        flag[i][j]=1;
                    else
                        flag[i][j]=flag[i][j-1]+1;
                }
                else
                    flag[i][j]=0;
            }
        max_1=0;
        for(int j=0;j<n;j++)
        {
            for(int i=0;i<m;i++)
            {
                if(flag[i][j]==0)
                    continue;
                depth=1;
                value=flag[i][j];
                x=i;
                while(x>0)
                {
                    if(flag[--x][j]>=value)
                        depth+=1;
                    else
                        break;
                }
                x=i;
                while(x<m-1)
                {
                    if(flag[++x][j]>=value)
                        depth+=1;
                    else
                        break;
                }
                max_1=max(max_1,depth*value);
            }
        }
        cout<<max_1<<endl;
    }
    return 0;
}
点赞