• 数组墙 最详细的解题报告


    题目

    随机给定一个整型数组,每个数组中的数字代表数组所在位置墙的高度,问这个数组所能拼凑的最大矩形墙的面积为多少。

    示例

    • 输入:{2, 1, 6, 5, 4, 7, 2}
    • 输出:16

    提示

    数组{2, 1, 6, 5, 4, 7, 2}可以描述为:

    2 1 6 5 4 7 2
    (color{#000000}{*})
    (color{#000000}{*}) (color{#000000}{*})
    (color{#000000}{*}) (color{#000000}{*}) (color{#000000}{*})
    (color{#FF3030}{*}) (color{#FF3030}{*}) (color{#FF3030}{*}) (color{#FF3030}{*})
    (color{#FF3030}{*}) (color{#FF3030}{*}) (color{#FF3030}{*}) (color{#FF3030}{*})
    (color{#000000}{*}) (color{#FF3030}{*}) (color{#FF3030}{*}) (color{#FF3030}{*}) (color{#FF3030}{*}) (color{#000000}{*})
    (color{#000000}{*}) (color{#000000}{*}) (color{#FF3030}{*}) (color{#FF3030}{*}) (color{#FF3030}{*}) (color{#FF3030}{*}) (color{#000000}{*})

    其中,

    • 第一行的数字表示数组中对应的值
    • 每一列中(color{#000000}{*})的个数加上(color{#FF3030}{*})的个数之和等于第一行中数组的值
    • (color{#FF3030}{*})表示最大的矩形墙面积

    解题思路

    1. 将原数组array复制一份到数组copy
    2. 新建一个数组area用来存储包含当前列的最大面积,初始值为0
    3. 将数组copy0元素切割成多个子数组用Coordinate对象来表示,其中Coordinate.startIndex表示子数组的起始下标,Coordinate.endIndex表示子数组的结束下标(但不包含),Coordinate.minValue表示子数组的最小值
    4. 将数组copy[i]中的值减去Coordinate.minValue,其中Coordinate.startIndex <= i < Coordinate.endIndex,根据数组area的值area[i] = Math.max(area[i], (array[i] - copy[i]) * (Coordinate.endIndex - Coordinate.startIndex))
    5. 重复3)4)遍历所有的Coordinate对象,直到按0元素切割不能获得有效Coordinate

    具体算法(Java版)

    public class FindMaxRectangle {
    
        public static void main(String[] args) {
            // 随机生成数组
            int[] array = generateArray(20);
            // 将数组打印出来
            System.out.println("当前数组:" + arrayToString(array));
            // 打印数组墙
            printArray(array);
            // 输出最大矩形墙的面积
            System.out.println("数组最大矩形墙的面积为:" + findMax(array));
        }
    
        /**
         * 查找最大矩形墙的面积
         */
        private static int findMax(int[] array) {
            int[] copy = new int[array.length]; // 记录运行时数组中的值
            int[] area = new int[array.length]; // 记录最大矩形墙的面积
            Queue<List<Coordinate>> queue = new LinkedList<>();
            for (int i = 0; i < array.length; i++) {
                copy[i] = array[i];
                area[i] = 0;
            }
            queue.offer(divideArray(copy));
            while (!queue.isEmpty()) {
                List<Coordinate> coordinates = queue.poll();
                // 没有任何有效的子数组
                if (coordinates.size() == 0)
                    break;
                for (Coordinate coordinate : coordinates) {
                    for (int i = coordinate.getStartIndex(); i < coordinate.getEndIndex(); i++) {
                        if (copy[i] > 0) {
                            // 减去最小值minValue
                            copy[i] -= coordinate.getMinValue();
                        }
                        // 计算子数组对应的最大矩阵墙面积
                        int value = (array[i] - copy[i]) *
                                (coordinate.getEndIndex() - coordinate.getStartIndex());
                        // 更新最大矩阵墙的面积
                        area[i] = Math.max(value, area[i]);
                    }
                }
                queue.offer(divideArray(copy));
            }
            // 查找最大的矩阵墙的面积
            int maxArea = 0;
            for (int i = 0; i < area.length; i++) {
                if (maxArea < area[i]) {
                    maxArea = area[i];
                }
            }
            return maxArea;
        }
    
        /**
         * 将数组按照0元素切分成多个子数组,子数组用Coordinate对象来记录
         */
        private static List<Coordinate> divideArray(int[] array) {
            List<Coordinate> coordinates = new ArrayList<>();
            int startIndex = -1, endIndex = -1, minValue = Integer.MAX_VALUE;
            for (int i = 0; i < array.length; i++) {
                if (array[i] != 0) {
                    if (startIndex == -1) {
                        startIndex = i;
                    }
                    if (array[i] < minValue) {
                        minValue = array[i];
                    }
                } else {
                    if (startIndex != -1) {
                        endIndex = i;
                        coordinates.add(new Coordinate(startIndex, endIndex, minValue));
                        startIndex = -1;
                        minValue = Integer.MAX_VALUE;
                    }
                }
            }
            if (startIndex != -1) {
                coordinates.add(new Coordinate(startIndex, array.length, minValue));
            }
            return coordinates;
        }
    
        /**
         * 随机生成指定长度的数组
         */
        private static int[] generateArray(int length) {
            int[] array = new int[length];
            Random random = new Random();
            for (int i = 0; i < array.length; i++) {
                int value = random.nextInt(10);
                if (value < 0) {
                    value = 0;
                }
                array[i] = value;
            }
            return array;
        }
    
        /**
         * 打印成数组墙
         */
        private static void printArray(int[] array) {
            int max = 0;
            for (int i = 0; i < array.length; i++) {
                if (max < array[i]) {
                    max = array[i];
                }
            }
            for (int i = max; i > 0; i--) {
                for (int j = 0; j < array.length; j++) {
                    if (array[j] >= i) {
                        System.out.print("* ");
                    } else {
                        System.out.print("  ");
                    }
                }
                System.out.println();
            }
        }
    
        /**
         * 将数组转换成字符串
         */
        private static String arrayToString(int[] array) {
            StringBuilder stringBuilder = new StringBuilder();
            stringBuilder.append("[");
            for (int i = 0; i < array.length; i++) {
                stringBuilder.append(array[i]);
                if (i != array.length - 1) {
                    stringBuilder.append(", ");
                }
            }
            stringBuilder.append("]");
            return stringBuilder.toString();
        }
    
        /**
         * 用来记录子数组信息
         */
        static class Coordinate {
            /**
             * @param startIndex 数组的起始下标
             * @param endIndex 数组的结束下标(不包含)
             * @param minValue 数组中的最小值
             */
            public Coordinate(int startIndex, int endIndex, int minValue) {
                this.startIndex = startIndex;
                this.endIndex = endIndex;
                this.minValue = minValue;
            }
    
            private int startIndex; // 数组的起始下标
            private int endIndex; // 数组的结束下标(不包含)
            private int minValue; // 数组中的最小值
    
            public int getStartIndex() {
                return startIndex;
            }
    
            public int getEndIndex() {
                return endIndex;
            }
    
            public int getMinValue() {
                return minValue;
            }
        }
    }
    

    输出结果

    运行结果

    如果大家有什么更好的方法或者发现代码中存在bug希望可以一起交流讨论!

  • 相关阅读:
    mvc
    拦截器
    使用HttpWebRequest和HtmlAgilityPack抓取网页(拒绝乱码,拒绝正则表达式)
    编译和解释的区别是什么?
    15 个最佳的 jQuery 表格插件
    编程小白必备——主流语言C语言知识点
    妹子找你修电脑,按照这几步操作,你就是黑客大佬!
    网络管理监视很重要!学编程的你知道哪些不错的网络监控工具?2020 最好的Linux网络监控工具分享给你
    为什么程序员要跳槽,钱并非第一位
    代码编写行为准则,编码是一个认真思考的过程,如何有效提高代码的可读性?
  • 原文地址:https://www.cnblogs.com/pinxiong/p/13513359.html
Copyright © 2020-2023  润新知