📣 独立日限时特惠: VIP通行证立减$68
查看: 2704| 回复: 5
跳转到指定楼层
上一主题 下一主题
收起左侧

一道OA难题求解

全局:

注册一亩三分地论坛,查看更多干货!

您需要 登录 才可以下载或查看附件。没有帐号?注册账号

x
题目是这样的。

一个boolean的M*N二维矩阵,由1和0组成。要求找出全部由1组成的正方形,从左上角开始,每次向右或者向下移动一格,到达右下角,途中不能遇到任何0。求满足这样条件最大的正方形的面积。

1 1 1 0
1 1 1 1
1 1 1 1
0 1 1 1
0 1 1 1

这个例子中,最大的面积是4,即2*2的矩形。
这题跟leetcode里的max rectangle area有点像,但是不同的是,那题会返回3*3,但是这题不行,因为中途3*3的矩形过不来。可以想成推箱子的游戏,求能通过的最大的箱子的size。

所以有人能帮忙想想该怎么做吗? 提示的worst case runtime 是 O(m*n*log(m+n)), 空间是 O(m*n)


上一篇:TripAdvisor IP找city问题
下一篇:211. Add and Search Word - Data structure design
推荐
ccarter 2016-3-13 22:33:29 | 只看该作者
全局:
应该是先预处理以每个点为左上角的最大正方形边长,然后二分答案

评分

参与人数 1大米 +10 收起 理由
忆梦前尘 + 10 回答的很好!

查看全部评分

回复

使用道具 举报

推荐
619899442 2017-12-7 05:18:48 | 只看该作者
全局:
本帖最后由 619899442 于 2017-12-7 05:21 编辑

我有一个不成熟的小想法:使用DP实现:
假设DP[j] 代表可以从左上角移动到(i, j) 的最大正方形,那么有三种方式使它移动到(i, j):
1. 无需移动
2. 从左到右
3. 从上到下

但是这样做的复杂度是O(mn), 跟楼主给的不太一样,所以我并不是很确定
  1. public class MaxMoveableRect {

  2.     private static int MaxMoveableRect(int [][] matrix) {
  3.         int m = matrix.length;
  4.         int n = matrix[0].length;
  5.         // allOnes[i][j] == whether the rectangle defined by (0,0) and (i, j) only
  6.         // contains 1
  7.         boolean [][] allOnes = new boolean [m][n];
  8.         allOnes[0][0] = (matrix[0][0] == 1) ? true: false;
  9.         for (int i = 1; i < m; ++i) {
  10.             allOnes[i][0] = allOnes[i-1][0] && (matrix[i][0] == 1);
  11.         }
  12.         for (int j = 1; j < n; ++j) {
  13.             allOnes[0][j] = allOnes[0][j-1] && (matrix[0][j] == 1);
  14.         }
  15.         for (int i = 1; i < m; ++i) {
  16.             for (int j = 1; j < n; ++j) {
  17.                 allOnes[i][j] = allOnes[i][j-1] && allOnes[i-1][j] && (matrix[i][j] == 1);
  18.             }
  19.         }

  20.         // ceiling[i][j] -- the row index of the ceiling 0 above matrix[i][j]
  21.         int [][] ceiling = new int [m][n];
  22.         for (int j = 0; j < n; ++j) {
  23.             ceiling[0][j] = (matrix[0][j] == 0) ? 0 : -1;
  24.         }
  25.         for (int i = 1; i < m; ++i) {
  26.             for (int j = 0; j < n; ++j) {
  27.                 ceiling[i][j] = (matrix[i][j] == 0) ? i : ceiling[i-1][j];
  28.             }
  29.         }

  30.         // tail[i][j] -- the col index if the tail (righmost) 0 on the left of matrix[i][j]
  31.         int [][] tail = new int [m][n];
  32.         for (int i = 0; i < m; ++i) {
  33.             tail[i][0] = (matrix[i][0] == 0) ? 0 : -1;
  34.         }
  35.         for (int i = 0; i < m; ++i) {
  36.             for (int j = 1; j < n; ++j) {
  37.                 tail[i][j] = (matrix[i][j] == 0) ? j : tail[i][j-1];
  38.             }
  39.         }




  40.         // the max edge length of all-one sequre that can be moved from (0, 0) to
  41.         // (i, j)
  42.         int [][] dp = new int [m][n];
  43.         dp[0][0] =  (matrix[0][0] == 1) ? 1 : 0;
  44.         for (int i = 1; i < m; ++i) {
  45.             dp[i][0] = (matrix[i][0] == 1) ? dp[i-1][0] : 0;
  46.         }
  47.         for (int j = 1; j < n; ++j) {
  48.             dp[0][j] = (matrix[0][j] == 1) ? dp[0][j-1] : 0;
  49.         }
  50.         for (int i = 1; i < m; ++i) {
  51.             for (int j = 1; j < n; ++j) {
  52.                 if (matrix[i][j] == 0) {
  53.                     dp[i][j] = 0;
  54.                 } else if (allOnes[i][j]) {
  55.                     dp[i][j] = Math.min(i + 1, j + 1);
  56.                 } else {
  57.                     dp[i][j] = Math.max(
  58.                         Math.min(dp[i][j-1], i - ceiling[i][j]),  // move from left to right
  59.                         Math.min(dp[i-1][j], j - tail[i][j])
  60.                     );
  61.                 }
  62.             }
  63.         }

  64.         return dp[m-1][n-1];
  65.     }


  66.     public static void main(String [] args) {

  67.         int [][] matrix = new int [][] {
  68.             {1,1,1,0},
  69.             {1,1,1,1},
  70.             {1,1,1,1},
  71.             {0,1,1,1},
  72.             {0,1,1,1}
  73.         };
  74.         System.out.println(MaxMoveableRect(matrix));

  75.     }

  76. }
复制代码

回复

使用道具 举报

🔗
 楼主| 忆梦前尘 2016-3-14 01:48:44 | 只看该作者
全局:
ccarter 发表于 2016-3-13 06:33
应该是先预处理以每个点为左上角的最大正方形边长,然后二分答案

哦,这个二分是怎么个二分法?比如例子里面以左上角为顶点的正方形可以是1,2,3.那么应该二分这个1,2,3么?
回复

使用道具 举报

🔗
ccarter 2016-3-14 23:48:49 | 只看该作者
全局:
忆梦前尘 发表于 2016-3-14 01:48
哦,这个二分是怎么个二分法?比如例子里面以左上角为顶点的正方形可以是1,2,3.那么应该二分这个1,2, ...

嗯,二分1~3,因为这个答案有这样的性质:如果答案为k,则任何小于等于k的一定能过去,任何大于k的一定过不去
但是我还没太想好预处理怎么O(mn)
回复

使用道具 举报

🔗
WLLiu 2016-3-15 06:43:07 | 只看该作者
全局:
check min(m,n)
if passable
    return min(m,n)
else
    h = min(m,n)
    l = 1
    m = (h+l) / 2
    while( h > l )
        check(m)
        if(passable)
            l = m + 1
        else
            h = m - 1
    end while
    return m

这样就行了。check(l)是检查变长为l的正方形能否从左上角通过到右下角,耗时O(mn),dfs搜索就行。一共检查log(min(m,n))次。
空间上,储存这个map要O(mn)所以就是O(mn)复杂度。
你们看对不对?

评分

参与人数 1大米 +3 收起 理由
xh_pku + 3 回答的很好!有道理~

查看全部评分

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册账号
隐私提醒:
  • ☑ 禁止发布广告,拉群,贴个人联系方式:找人请去🔗同学同事飞友,拉群请去🔗拉群结伴,广告请去🔗跳蚤市场,和 🔗租房广告|找室友
  • ☑ 论坛内容在发帖 30 分钟内可以编辑,过后则不能删帖。为防止被骚扰甚至人肉,不要公开留微信等联系方式,如有需求请以论坛私信方式发送。
  • ☑ 干货版块可免费使用 🔗超级匿名:面经(美国面经、中国面经、数科面经、PM面经),抖包袱(美国、中国)和录取汇报、定位选校版
  • ☑ 查阅全站 🔗各种匿名方法

本版积分规则

>
快速回复 返回顶部 返回列表