zoukankan      html  css  js  c++  java
  • [AtCoder] Mandarin Orange

    Problem Link: C - Mandarin Orange

    The problem can be converted to as such: Given an array A of positive integers, find out the the maximum product value Len * Min{L, R}. Len is the length of subarray A[L, R] and Min{L, R} is the minimum value in this subarray. 

    Solution 1. O(N^3) brute force

    Obviously we can just check all O(N^2) subarrays, each check takes O(N) time to find a subarray min value. 

    Solution 2. O(N^2 * logN), optimizing min value check using segment tree

        static class SegmentTree {
            int leftMost, rightMost;
            SegmentTree lChild, rChild;
            int min;
    
            SegmentTree(int leftMost, int rightMost, int[] a) {
                this.leftMost = leftMost;
                this.rightMost = rightMost;
                if(leftMost == rightMost) {
                    min = a[leftMost];
                }
                else {
                    int mid = leftMost + (rightMost - leftMost) / 2;
                    lChild = new SegmentTree(leftMost, mid, a);
                    rChild = new SegmentTree(mid + 1, rightMost, a);
                    recalc();
                }
            }
    
            void recalc() {
                if(leftMost == rightMost) return;
                min = Math.min(lChild.min, rChild.min);
            }
    
            void pointUpdate(int index, int newVal) {
                if(leftMost == rightMost) {
                    min = newVal;
                    return;
                }
                if(index <= lChild.rightMost) lChild.pointUpdate(index, newVal);
                else rChild.pointUpdate(index, newVal);
                recalc();
            }
    
            int minQuery(int l, int r) {
                if(l > rightMost || r < leftMost) return Integer.MAX_VALUE;
                if(l <= leftMost && r >= rightMost) return min;
                return Math.min(lChild.minQuery(l, r), rChild.minQuery(l, r));
            }
        }
    
        static void solve(int testCnt) {
            for (int testNumber = 0; testNumber < testCnt; testNumber++) {
                int n = in.nextInt();
                int[] a = in.nextIntArrayPrimitive(n);
                SegmentTree st = new SegmentTree(0, n - 1, a);
                int ans = 0;
                for(int l = 0; l < n; l++) {
                    for(int r = l; r < n; r++) {
                        ans = Math.max(ans, st.minQuery(l, r) * (r - l + 1));
                    }
                }
                out.println(ans);
            }
            out.close();
        }

    Solution 3. O(N^2), optimizing min value check by pre-computing the range min query sparse table in O(N * logN) time and space. 

        static class RangeMinQuery_SparseTable {
            int n, k;
            int[] log;
            int[][] rangeMin;
    
            public RangeMinQuery_SparseTable(int[] a) {
                n = a.length;
                log = new int[n + 1];   //log[i]: 2^log[i] = i; for i that is not 2^j, log[i] rounds down to the closest such 2^j that 2^j < i
                log[1] = 0; //2^0 = 1
                //precompute log
                for (int i = 2; i <= n; i++) {
                    log[i] = log[i / 2] + 1;
                }
                k = log[n]; //if n is not 2^j, k is rounded down, so when initializing rangeMin we need to use k + 1
                rangeMin = new int[n][k + 1];
                for(int i = 0; i < n; i++) {
                    rangeMin[i][0] = a[i];
                }
                //rangeMin[i][j] is the min in range[i, i + 2^j - 1] of length 2^j
                for(int j = 1; j <= k; j++) {
                    for(int i = 0; i + (1 << j) <= n; i++) {
                        rangeMin[i][j] = Math.min(rangeMin[i][j - 1], rangeMin[i + (1 << (j - 1))][j - 1]);
                    }
                }
            }
    
            public int query(int L, int R) {
                //2^j is at least half the size of range [L, R], at most the entire size of range[L, R]
                int j = log[R - L + 1];
                return Math.min(rangeMin[L][j], rangeMin[R - (1 << j) + 1][j]);
            }
        }
        static void solve(int testCnt) {
            for (int testNumber = 0; testNumber < testCnt; testNumber++) {
                int n = in.nextInt();
                int[] a = in.nextIntArrayPrimitive(n);
                RangeMinQuery_SparseTable rmst = new RangeMinQuery_SparseTable(a);
                int ans = 0;
                for(int l = 0; l < n; l++) {
                    for(int r = l; r < n; r++) {
                        ans = Math.max(ans, rmst.query(l, r) * (r - l + 1));
                    }
                }
                out.println(ans);
            }
            out.close();
        }

      

    Solution 4. O(N^2), fixing L, then update min value while increasing R one by one. (Keep a running min)

        static void solve(int testCnt) {
            for (int testNumber = 0; testNumber < testCnt; testNumber++) {
                int n = in.nextInt();
                int[] a = in.nextIntArrayPrimitive(n);
                int ans = 0;
                for(int l = 0; l < n; l++) {
                    int currMin = a[l];
                    for(int r = l; r < n; r++) {
                        currMin = Math.min(currMin, a[r]);
                        ans = Math.max(ans, currMin * (r - l + 1));
                    }
                }
                out.println(ans);
            }
            out.close();
        }

      

    Solution 5. O((maxV + N) * logN).

    Using the fact that max of A's element is only up to O(10^5), we can iterate over all min value candidates and find the max answer. This is done as following. 

    1.   Create a tree mapping from A[i] to all of its indices in A, call it tm. 

    2.  Create a tree set that stores all the smaller values' indices, call it prevIdx. 

    3.  From 1 to max possible value in A, do the following:

    (a). if the current value exists in A, iterate over all of its indices and for each index i find the largest index l such that l < i and the smallest index r such that r > i. l and r are the left and right boundaries of the the current value at index i being the min value. 

    (b). after (a), add of the indices of the current value to prevIdx for bigger value checks.

    The runtime is O((maxV + N) * logN). We need to iterare from 1 to maxV. And there are N total indices to all to prevIdx. For each of these N indices, we do 2 logN operations to get the left and right boundaries. Lastly, the tree map has at most N entries, we do maxV existence check, each costs O(logN) time. 

        static void solve(int testCnt) {
            for (int testNumber = 0; testNumber < testCnt; testNumber++) {
                int n = in.nextInt();
                int[] a = in.nextIntArrayPrimitive(n);
                int maxV = 0;
                for(int v : a) {
                    maxV = Math.max(maxV, v);
                }
                TreeMap<Integer, List<Integer>> tm = new TreeMap<>();
                for(int i = 0; i < n; i++) {
                    tm.computeIfAbsent(a[i], k -> new ArrayList<>()).add(i);
                }
                TreeSet<Integer> prevIdx = new TreeSet<>();
                int ans = 0;
                for(int x = 1; x <= maxV; x++) {
                    if(tm.containsKey(x)) {
                        List<Integer> idx = tm.get(x);
                        for(int i : idx) {
                            Integer l = prevIdx.lower(i);
                            Integer r = prevIdx.higher(i);
                            if(l == null) {
                                l = -1;
                            }
                            if(r == null) {
                                r = n;
                            }
                            ans = Math.max(ans, (r - l - 1) * x);
                        }
                        prevIdx.addAll(idx);
                    }
                }
                out.println(ans);
            }
            out.close();
        }

    Solution 6. O(N), this problem is the same with finding the largest rectangle in histogram. Treat each A[i] as a histogram height at index i. 

    Keep a non-decreasing stack, each time the current a[i] is smaller than the top of the stack j, we just find the right bound of the rectangle of height h[j]. Its left bound is just beneath itself in the stack. After iterating over all a[i] and if there are still unprocessed heights in the stack, repeat the same popping process using N as their right bound. 

     

        static void solve(int testCnt) {
            for (int testNumber = 0; testNumber < testCnt; testNumber++) {
                int n = in.nextInt();
                int[] a = in.nextIntArrayPrimitive(n);
                ArrayDeque<Integer> q = new ArrayDeque<>();
                q.addFirst(-1);
                int ans = 0;
                for(int i = 0; i < n; i++) {
                    while(q.peekFirst() >= 0 && a[q.peekFirst()] > a[i]) {
                        int j = q.removeFirst();
                        ans = Math.max(ans, (i - q.peekFirst() - 1) * a[j]);
                    }
                    q.addFirst(i);
                }
                while(q.peekFirst() >= 0) {
                    int idx = q.removeFirst();
                    ans = Math.max(ans, (n - q.peekFirst() - 1) * a[idx]);
                }
                out.println(ans);
            }
            out.close();
        }

    Related Problems:

    [LeetCode 84] Largest Rectangle in Histogram

  • 相关阅读:
    南京航空航天大学软件著作权申请办法
    CoDel Test Script
    [编辑中] 免费的Internet流量发生器 | Free Internet Traffic Generators
    关于Java LDAP登录集成
    sonar + ieda实现提交代码前代码校验
    sonar+Jenkins代码覆盖率检测
    定义自己的代码风格CheckStyle简单使用
    HAProxy简单使用
    读取大文件性能测试
    使用HtmlUnit登录百度
  • 原文地址:https://www.cnblogs.com/lz87/p/14324972.html
Copyright © 2011-2022 走看看