【程序员面试金典】面试题 17.23. 最大黑方阵

这篇具有很好参考价值的文章主要介绍了【程序员面试金典】面试题 17.23. 最大黑方阵。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

题目描述

描述:给定一个方阵,其中每个单元(像素)非黑即白。设计一个算法,找出 4 条边皆为黑色像素的最大子方阵。

返回一个数组 [r, c, size] ,其中 r, c 分别代表子方阵左上角的行号和列号,size 是子方阵的边长。若有多个满足条件的子方阵,返回 r 最小的,若 r 相同,返回 c 最小的子方阵。若无满足条件的子方阵,返回空数组。

示例 1:

输入:
[
   [1,0,1],
   [0,0,1],
   [0,0,1]
]
输出: [1,0,2]
解释: 输入中 0 代表黑色,1 代表白色,标粗的元素即为满足条件的最大子方阵

示例 2:

输入:
[
   [0,1,1],
   [1,0,1],
   [1,1,0]
]
输出: [0,0,1]

提示:

matrix.length == matrix[0].length <= 200

解题思路

思路:最直观的想法是,穷举。依次遍历从矩阵中某一点开始出发的最大子矩阵,在遍历某一点时,先判断其向右方向的最大值,然后再从该最大值逐渐减小去判断以该点为左上角的子矩阵是否四边均是黑边,同步更新最大值即可。(超时36/37)

class Solution {
public:
    //从(i,j)出发右边长度为size的
    bool check(vector<vector<int>>& matrix,int i,int j,int size,int m,int n)
    {
        //某一边不够长度
        if(i+size-1>=m||j+size-1>=n)
            return false;
        //左边
        for(int k=i;k<i+size;k++)
        {
            if(matrix[k][j]!=0)
                return false;
        }
        //下边
        for(int k=j;k<j+size;k++)
        {
            if(matrix[i+size-1][k]!=0)
                return false;
        }
        //右边
        for(int k=i;k<i+size;k++)
        {
            if(matrix[k][j+size-1]!=0)
                return false;
        }
        return true;
    }
    vector<int> findSquare(vector<vector<int>>& matrix) {
        int m=matrix.size();
        if(m==0)
            return vector<int>();
        int n=matrix[0].size();
        vector<int> res(3,-1);
        //从左向右从上向下遍历矩阵
        for(int i=0;i<m;i++)
        {
            for(int j=0;j<n;j++)
            {
                //假设当前为黑色则只向一个方向遍历找到黑色最大边
                if(matrix[i][j]==0)
                {
                    //标记一下当前位置开始右边最大的边
                    int size=0;
                    //cout<<i<<" "<<j<<" "<<size<<endl;
                    //从(i,j)向右找到黑色最大长度
                    for(int k=j;k<n;k++)
                    {
                        if(matrix[i][k]==0)
                            size++;
                        else 
                            break;
                    }
                    //cout<<i<<" "<<j<<" "<<size<<endl;
                    bool flag=false;
                    //判断四边是否满足
                    while(size>=1)
                    {
                        if(check(matrix,i,j,size,m,n)&&size>res[2])
                        {
                            flag=true;
                            res[0]=i;
                            res[1]=j;
                            res[2]=size;
                            break;
                        }
                        //从最大到最小
                        size--;
                    }
                }
            }
        }
        //判断
        return res[0]==-1?vector<int> ():res;
    }
};

优化:动态规划。dp[r][c][0/1]分别表示以坐标(r,c)为起点向右/下最多的连续黑色块数量。由于是向右/向下,故从下向上遍历从右向左遍历,即逆向更新即可,其中根据行来更新向下,根据列来更新向右。注意,以坐标(r,c)为左上角的子矩阵边长为向右和向下最多的连续黑色块数量两者中的最小值,此时还需要满足(r+len-1,c)向右和(r,c+len-1)向下最多的连续黑色块数量大于等于len才行!!!

class Solution {
public:
    vector<int> findSquare(vector<vector<int>>& matrix) {
        vector<int> res(3,0);
        int n=matrix.size();
        if(n==0)
            return {};
        if(n==1)
        {
            if(matrix[0][0]==0)
                return {0,0,1};
            else
                return {};
        }
        //dp[r][c][0/1]代表以坐标(r,c)为起点向右/下最多的连续黑色块数量
        vector<vector<vector<int>>> dp(n,vector<vector<int>>(n,vector<int>(2)));
        //逆向遍历
        for(int r=n-1;r>=0;r--)
        {
            for(int c=n-1;c>=0;c--)
            {
                //当前为1则连续黑色均为0
                if(matrix[r][c]==1)
                {
                    dp[r][c][0]=0;
                    dp[r][c][1]=0;
                }
                else
                {
                    //根据r统计下方
                    if(r<n-1)
                        dp[r][c][1]=dp[r+1][c][1]+1;
                    else
                        dp[r][c][1]=1;
                    //根据c统计右方
                    if(c<n-1)
                        dp[r][c][0]=dp[r][c+1][0]+1;
                    else
                        dp[r][c][0]=1;
                    //更新当前最大子方针
                    int len=min(dp[r][c][0],dp[r][c][1]);
                    while(len>=res[2])
                    {
                        //当前右边和下边 也要保证下边右方和右边下方
                        if(dp[r+len-1][c][0]>=len&&dp[r][c+len-1][1]>=len)
                        {
                            res={r,c,len};
                            break;
                        }
                        len--;
                    }
                }
            }
        }
        return res;
    }
};

总结:超时,则说明需要优化时间复杂度,再来看,存在重复子问题,即黑色块数量是连续的,故此时就涉及到递推公式,这不就想到了动态规划!文章来源地址https://www.toymoban.com/news/detail-519127.html

到了这里,关于【程序员面试金典】面试题 17.23. 最大黑方阵的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【程序员面试金典】面试题 17.25 . 单词矩阵

    描述:给定一份单词的清单,设计一个算法,创建由字母组成的面积最大的矩形,其中每一行组成一个单词(自左向右),每一列也组成一个单词(自上而下)。不要求这些单词在清单里连续出现,但要求所有行等长,所有列等高。 如果有多个面积最大的矩形,输出任意一个均可

    2024年02月12日
    浏览(45)
  • 【程序员面试金典】面试题 17.19. 消失的两个数字

    描述:给定一个数组,包含从 1 到 N 所有的整数,但其中缺了两个数字。你能在 O(N) 时间内只用 O(1) 的空间找到它们吗? 以任意顺序返回这两个数字均可。 示例 1: 示例 2: 提示: nums.length = 30000 思路:最直观的想法是,位运算。消失的两个数字和只出现一次的两个元素,本质

    2024年02月12日
    浏览(52)
  • 【程序员面试金典】面试题 17.14. 最小K个数

    描述:设计一个算法,找出数组中最小的k个数。以任意顺序返回这k个数均可。 示例: 提示: 0 = len(arr) = 100000 0 = k = min(100000, len(arr)) 思路:最直观的想法是,排序。 扩展:最大堆。最小的k个数,那么就可以维持一个大小为k的最大堆,先填充k个数到最大堆中,然后再依次遍

    2024年02月11日
    浏览(55)
  • 【程序员面试金典】面试题 17.21. 直方图的水量

    描述:给定一个直方图(也称柱状图),假设有人从上面源源不断地倒水,最后直方图能存多少水量?直方图的宽度为 1。 上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的直方图,在这种情况下,可以接 6 个单位的水(蓝色部分表示水)。 感谢 Marcos 贡献此图。 示例: 思路:最直观的想

    2024年02月11日
    浏览(42)
  • 面试题 17.23. 最大黑方阵

    题目链接 找到最长的边都是0的正方形,如果长度想等,尽可能起点小 暴力+剪枝 dp ,预处理每个点的上下左右最长长度,再去枚举长度去转移

    2024年02月21日
    浏览(62)
  • 《程序员面试金典(第6版)面试题 16.10. 生存人数(前缀和思想)

    给定 N 个人的出生年份和死亡年份,第 i 个人的出生年份为 birth[i],死亡年份为 death[i],实现一个方法以计算生存人数最多的年份。 你可以假设所有人都出生于 1900 年至 2000 年(含 1900 和 2000 )之间。如果一个人在某一年的任意时期处于生存状态,那么他应该被纳入那一年的

    2024年02月02日
    浏览(53)
  • 《程序员面试金典(第6版)》 面试题 08.11. 硬币(动态规划,组合问题,C++)

    硬币。给定数量不限的硬币,币值为25分、10分、5分和1分,编写代码计算n分有几种表示法。(结果可能会很大,你需要将结果模上1000000007) 示例1: 输入: n = 5 输出:2 解释: 有两种方式可以凑成总金额: 5=5 5=1+1+1+1+1 示例2: 输入: n = 10 输出:4 解释: 有四种方式可以凑成总金额: 1

    2023年04月08日
    浏览(54)
  • 读程序员的README笔记17_构建可演进的架构(下)

    1.3.3.1. 开发人员可以只专注于和自己相关的字段,因为它们会继承其他字段的默认值 1.3.3.2. 默认值可使大型API在感觉上很小巧 1.4.1.1. OpenAPI通常用于RESTful服务 1.4.1.2. non-REST服务则使用Protocol Buffers、Thrift或类似的接口定义语言(interface definition language,IDL) 1.4.1.3. 接口定义工

    2024年02月04日
    浏览(57)
  • 程序员面试逻辑题

    答案: 这个题有点像数学归纳法,就是假设有 A A A 和 B B B 两个人是黑色的帽子,这样的话第一次开灯, A A A 看到 B B B 是黑色的,其他人都是白色的,那么 A A A 会觉得 B B B 是那个黑色的,同理 B B B 也是这么想的。一次关灯之后 A A A 和 B B B 都没有打耳光, A A A 反应过来

    2024年02月09日
    浏览(89)
  • 程序员必备的面试技巧

    “程序员必备的面试技巧,就像是编写一段完美的代码一样重要。在面试战场上,我们需要像忍者一样灵活,像侦探一样聪明,还要像无敌铁金刚一样坚定。只有掌握了这些技巧,我们才能在面试的舞台上闪耀光芒,成为那个令HR们心动的程序猿!” 提醒:在发布作品前,请

    2024年01月21日
    浏览(55)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包