平面灯阵中寻找最大正方形边界 - 华为机试真题题解

分值: 300分

题解: Java / Python / C++

alt

题目描述

现在有一个二维数组来模拟一个平面灯阵,平面灯阵中每个位置灯处于点亮或熄灭,分别对应数组每个元素取值只能为1或0,现在需要找一个正方形边界,其每条边上的灯都是点亮(对应数组中元素的值为1)的,且该正方形面积最大。

输入描述

第一行为灯阵的高度(二维数组的行数)

第二行为灯阵的宽度(二维数组的列数)

紧接着为模拟平台灯阵的二维数组arr

1< arr.length <= 200 1< arr[0].length <= 200

输出描述

返回满足条件的面积最大正方形边界信息。返回信息[r,c,w],其中r,c分别代表方阵右下角的行号和列号,w代表正方形的宽度。如果存在多个满足条件的正方形,则返回r最小的,若r相同,返回c最小的正方形。

示例1

输入:
4
5
1 0 0 0 1
1 1 1 1 1
1 0 1 1 0
1 1 1 1 1

输出:
[3,2,3]

解释:
满足条件且面积最大的正方形边界,其右下角的顶点为[3,2],即行号为3,列号为2,其宽度为3,因此返回信息为[3,2,3]。

示例2

输入:
3
3
1 0 0
0 1 0
0 0 1

输出:
[0,0,1]

解释:
满足条件且面积最大的正方形边界有三个。即为[0,0,1]、[1,1,1]、[2,2,1],根据要求,如果满足条件有多个,则返r最小,即为 [0,0,1]。

题解

动态规划的题目

解题思路

首先,我们需要计算每个位置的左侧和上侧连续为1的数量,以便在后续判断正方形边界时使用。(在代码实现中使用 row_psum 和 col_psum 来实现)

然后,我们遍历二维数组,对每个点 (r, c),检查以该点为右下角的正方形边界,看是否满足条件。

最终,找到满足条件的最大正方形边界,返回其右下角的行号、列号和边长。

Java

import java.util.Scanner;

/**
 * @author code5bug
 */
public class Main {
    // 检查以(r,c)为正方形,宽度为 w 的正方形边界的灯是否都是点亮的
    static boolean check(int[][] row_psum, int[][] col_psum, int r, int c, int w) {
        // 下,右边检查
        if (row_psum[r][c] < w || col_psum[r][c] < w) return false;

        // 左、上边检查
        if (col_psum[r][c - w + 1] < w || row_psum[r - w + 1][c] < w) return false;

        return true;
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int h = scanner.nextInt();
        int w = scanner.nextInt();

        int[][] g = new int[h][w];
        for (int r = 0; r < h; r++) {
            for (int c = 0; c < w; c++) {
                g[r][c] = scanner.nextInt();
            }
        }

        // row_psum[r][c] 表示 (r,c) 左侧连续 1 的数量
        int[][] row_psum = new int[h][w];
        // col_psum[r][c] 表示 (r,c) 上侧连续 1 的数量
        int[][] col_psum = new int[h][w];

        for (int r = 0; r < h; r++) {
            for (int c = 0; c < w; c++) {
                if (g[r][c] == 0) continue;

                row_psum[r][c] = (c > 0 ? row_psum[r][c - 1] : 0) + 1;
                col_psum[r][c] = (r > 0 ? col_psum[r - 1][c] : 0) + 1;
            }
        }

        // [r, c, w]
        int[] result = new int[3];

        for (int r = 0; r < h; r++) {
            for (int c = 0; c < w; c++) {
                if (g[r][c] == 0) continue;

                for (int width = Math.min(r

剩余60%内容,订阅专栏后可继续查看/也可单篇购买

华为OD机试题库题解2024 文章被收录于专栏

华为OD机考(CDE卷)题库(绝对都是原题),帮助你上岸华为(已经不少小伙伴成功上岸)。提供Java、Python、C++ 三种语言的解法。每篇文章都有详细的解题步骤、代码注释详细及相关知识点的练习题。有问题,随时解答。

全部评论
这个解法太复杂了,直接令dp[i][j]为以i,j为右下角的最大正方形的边长,递推式为 dp[i][j] = min(dp[i-j][j-1],dp[i-1][j],dp[i][j-1])+1)
2 回复 分享
发布于 04-25 09:59 浙江
不是只有200分吗
点赞 回复 分享
发布于 2023-12-29 03:30 四川
才想起来,这个400分的和600分的题有重复吗,还是完全不同的两套卷子
点赞 回复 分享
发布于 04-10 21:46 四川

相关推荐

7 12 评论
分享
牛客网
牛客企业服务