题解/算法 {包含所有 1 的最小矩形面积 II}

题解/算法 {包含所有 1 的最小矩形面积 II}

@LINK: https://leetcode.cn/problems/find-the-minimum-area-to-cover-all-ones-ii/;

虽然数据范围很小, 但没找到思路的话 还是很难的… 思维题

首先我们思考下两个的情况, 即网格空间里 有两个不会相互覆盖的矩形, 此时有一个性质: 你一定可以找到一个水平/垂直线 将整个空间切割为两部分 每个矩阵在每个部分里面;

 |               A A  
A|               _____
A|B B              B B
 |B B              B B

这个性质 推广到三个的情况里 同样是适用的, 即网格空间里有三个不相互覆盖的矩阵, 你可以找到一个水平/垂直线 将整个空间切割为两个部分 然后每个部分 至少有1个矩阵;

C C C                C C C|
_______                   |A A B
  A                       |A A B
  A B B                   |    B 
    B B                   |

这个性质 还是挺难想到的…
怎么证明呢? 你可以从两个的情况 推广过来, 即两个的情况时 此时你得到了一个切割线(垂直), 然后此时你再添加一个矩形: 如果这个矩阵和这个切割线冲突 那么其实可以发现 此时会存在一个水平的切割线;

假设这个切割线是水平的, 他可以划分成3种情况:

  A                  A                     B|C
_____              _____                  ______
  B                 B|C                     A
 ___
  C

如果切割线是垂直的 那么也是有3种情况 类似的(||, -|, |-), 我们可以将垂直的情况 将矩阵转置一下 从而变成处理上面水平切割线的情况;

到了这里 就简单多了, 无非就是枚举这3种情况, 时间是30*30 * 30*30 = 1e6;

int minimumSum(vector<vector<int>>& A) {
    int ANS = 1e9;
    auto Area = [&]( int _lx, int _ly, int _rx, int _ry)->int{
        int N = A.size(), M = A.front().size();
        if( _lx<0 || _lx>=N || _rx<0 || _rx>=N || _ly<0 || _ly>=M || _ry<0 || _ry>=M || _lx>_rx || _ly>_ry){ return -1;}
        int Lx = 1e9, Rx = -Lx, Ly = Lx, Ry = Rx;
        FOR_( i, _lx, _rx){
            FOR_( j, _ly, _ry){
                if( A[i][j] == 0){ continue;}
                Lx = min( Lx, i);  Rx = max( Rx, i);
                Ly = min( Ly, j);  Ry = max( Ry, j);
            }
        }
        if( Lx == int(1e9)){ return -1;}
        return (Rx-Lx+1) * (Ry-Ly+1);
    };
    auto Work = [&](){
        int N = A.size(), M = A.front().size();
        {
            FOR_( r0, 0, N-1){
                FOR_( r1, r0+1, N-1){
                    vector<int> res = {Area( 0, 0, r0, M-1), Area( r0+1, 0, r1, M-1), Area( r1+1, 0, N-1, M-1)};
                    if( std::count( res.begin(), res.end(), -1) != 0){ continue;}
                    ANS = min( ANS, std::accumulate( res.begin(), res.end(), 0));
                }
            }
        }
        {
            FOR_( r, 0, N-1){
                FOR_( c, 0, M-1){
                    vector<int> res = {Area( 0, 0, r, M-1), Area( r+1, 0, N-1, c), Area( r+1, c+1, N-1, M-1)};
                    if( std::count( res.begin(), res.end(), -1) != 0){ continue;}
                    ANS = min( ANS, std::accumulate( res.begin(), res.end(), 0));
                }
            }
        }
        {
            FOR_( r, 0, N-1){
                FOR_( c, 0, M-1){
                    vector<int> res = {Area( 0, 0, r, c), Area( 0, c+1, r, M-1), Area( r+1, 0, N-1, M-1)};
                    if( std::count( res.begin(), res.end(), -1) != 0){ continue;}
                    ANS = min( ANS, std::accumulate( res.begin(), res.end(), 0));
                }
            }
        }
    };
    Work();
    { // inverse
        vector temp( A.front().size(), vector<int>( A.size()));
        FOR_( i, 0, A.size()-1){
            FOR_( j, 0, A.front().size()-1){
                temp[ j][ i] = A[i][j];
            }
        }
        A = std::move( temp);
    }
    Work();
    ASSERT_( ANS != (int)1e9);
    return ANS;
}
  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值