1 条题解

  • 0
    @ 2025-7-3 18:47:55

    JAVA题解:

    import java.io.*;
    import java.util.*;
    
    public class Main {
        public static void main(String[] args) throws IOException {
            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
            int n = Integer.parseInt(br.readLine().trim());
            int[] h = Arrays.stream(br.readLine().trim().split(" "))
                    .mapToInt(Integer::parseInt)
                    .toArray();
            
            System.out.println(maxRectangleAreaAfterSwap(n, h));
        }
        
        public static int maxRectangleAreaAfterSwap(int n, int[] h) {
            // 1) 基准:单调栈求最大矩形面积(不交换)
            int base = maxAreaNoSwap(h);
            
            // 2) 构建稀疏表 RMQ(区间最小值查询)
            int LOG = 32 - Integer.numberOfLeadingZeros(n);
            int[][] st = new int[LOG][n];
            
            // 初始化稀疏表第一层
            System.arraycopy(h, 0, st[0], 0, n);
            
            // 构建稀疏表
            for (int k = 1; k < LOG; k++) {
                for (int i = 0; i + (1 << k) <= n; i++) {
                    st[k][i] = Math.min(st[k-1][i], st[k-1][i + (1 << (k-1))]);
                }
            }
            
            // 预计算log2
            int[] log2 = new int[n + 1];
            for (int i = 2; i <= n; i++) {
                log2[i] = log2[i / 2] + 1;
            }
            
            // 3) 排序统计 >= H 的数量
            int[] hs = h.clone();
            Arrays.sort(hs);
            
            int ans = base;
            
            for (int i = 0; i < n; i++) {
                int H = h[i];
                
                // 中心最大区间 [l0..r0]
                int l0 = findLeftmost(0, i, H, st, log2);
                int r0 = findRightmost(i, n - 1, H, st, log2);
                
                if (l0 == -1 || r0 == -1) continue;
                
                int w0 = r0 - l0 + 1;
                
                // 左侧延伸
                int wLeft = 0;
                if (l0 >= 2) {
                    int end = l0 - 2;
                    int stl = findLeftmost(0, end, H, st, log2);
                    if (stl != -1) {
                        wLeft = end - stl + 1;
                    }
                }
                
                // 右侧延伸
                int wRight = 0;
                if (r0 + 2 <= n - 1) {
                    int stp = findRightmost(r0 + 2, n - 1, H, st, log2);
                    if (stp != -1) {
                        wRight = stp - (r0 + 2) + 1;
                    }
                }
                
                int totalGood = countGreaterOrEqual(hs, H);
                int w = w0 + 1 + Math.max(wLeft, wRight);
                w = Math.min(w, totalGood);
                
                ans = Math.max(ans, w * H);
            }
            
            return ans;
        }
        
        // 单调栈求最大矩形面积
        private static int maxAreaNoSwap(int[] heights) {
            int n = heights.length;
            Stack<Integer> stack = new Stack<>();
            stack.push(-1);
            int maxArea = 0;
            
            for (int i = 0; i <= n; i++) {
                int current = (i == n) ? 0 : heights[i];
                while (stack.peek() != -1 && heights[stack.peek()] >= current) {
                    int height = heights[stack.pop()];
                    int width = i - stack.peek() - 1;
                    maxArea = Math.max(maxArea, height * width);
                }
                stack.push(i);
            }
            
            return maxArea;
        }
        
        // RMQ查询
        private static int rmq(int l, int r, int[][] st, int[] log2) {
            int k = log2[r - l + 1];
            return Math.min(st[k][l], st[k][r - (1 << k) + 1]);
        }
        
        // 二分查找最左边满足条件的位置
        private static int findLeftmost(int L, int R, int H, int[][] st, int[] log2) {
            int ans = -1;
            int l = L, r = R;
            
            while (l <= r) {
                int m = (l + r) / 2;
                if (rmq(m, R, st, log2) >= H) {
                    ans = m;
                    r = m - 1;
                } else {
                    l = m + 1;
                }
            }
            
            return ans;
        }
        
        // 二分查找最右边满足条件的位置
        private static int findRightmost(int L, int R, int H, int[][] st, int[] log2) {
            int ans = -1;
            int l = L, r = R;
            
            while (l <= r) {
                int m = (l + r) / 2;
                if (rmq(L, m, st, log2) >= H) {
                    ans = m;
                    l = m + 1;
                } else {
                    r = m - 1;
                }
            }
            
            return ans;
        }
        
        // 计算数组中大于等于x的元素个数
        private static int countGreaterOrEqual(int[] sorted, int x) {
            int idx = Arrays.binarySearch(sorted, x);
            if (idx < 0) {
                idx = -(idx + 1);
            } else {
                // 找到第一个大于等于x的位置
                while (idx > 0 && sorted[idx - 1] == x) {
                    idx--;
                }
            }
            return sorted.length - idx;
        }
    }
    
    
    • 1

    25年6月-华为实习-3.矩形面积最大化

    信息

    ID
    23
    时间
    1000ms
    内存
    256MiB
    难度
    7
    标签
    递交数
    4
    已通过
    1
    上传者