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

  • 相关阅读:
    poj 3321 Apple Tree
    hdu 1520 Anniversary party
    Light OJ 1089 Points in Segments (II)
    Timus 1018 Binary Apple Tree
    zoj 3299 Fall the Brick
    HFUT 1287 法默尔的农场
    Codeforces 159C String Manipulation 1.0
    GraphQL + React Apollo + React Hook 大型项目实战(32 个视频)
    使用 TypeScript & mocha & chai 写测试代码实战(17 个视频)
    GraphQL + React Apollo + React Hook + Express + Mongodb 大型前后端分离项目实战之后端(19 个视频)
  • 原文地址:https://www.cnblogs.com/lz87/p/14324972.html
Copyright © 2011-2022 走看看