隨機給定一個整型數組,每一個數組中的數字表明數組所在位置牆的高度,問這個數組所能拼湊的最大矩形牆的面積爲多少。java
數組{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}{*}\) |
其中,數組
array
複製一份到數組copy
area
用來存儲包含當前列的最大面積,初始值爲0
copy
按0
元素切割成多個子數組用Coordinate
對象來表示,其中Coordinate.startIndex
表示子數組的起始下標,Coordinate.endIndex
表示子數組的結束下標(但不包含),Coordinate.minValue
表示子數組的最小值copy[i]
中的值減去Coordinate.minValue
,其中Coordinate.startIndex <= i < Coordinate.endIndex
,根據數組area
的值area[i] = Math.max(area[i], (array[i] - copy[i]) * (Coordinate.endIndex - Coordinate.startIndex))
3)
和4)
遍歷全部的Coordinate
對象,直到按0元素切割不能得到有效Coordinate
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但願能夠一塊兒交流討論!app