Minimum Range Query

Minimum Range Queries

Presentation

Most Beautiful Item for Each Query

Problem description

Most Beautiful Item for Each Query

Initial processing

```java linenums=”1” import java.util.Arrays; class Solution { public int[] maximumBeauty(int[][] items, int[] queries) { Arrays.sort(items, (a, b) -> Integer.compare(a[0], b[0]));

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
    // get the unique prices and max beauty for each unique price
    int[] tmpPrices = new int[items.length];
    int[] tmpBeauty = new int[items.length];
    tmpPrices[0] = items[0][0];
    tmpBeauty[0] = items[0][1];
    int pCount = 0;
    for (int i = 1; i < items.length; i++ ) {
        if (items[i][0] == tmpPrices[pCount]) {
            if (items[i][1] > tmpBeauty[pCount]) {
                tmpBeauty[pCount] = items[i][1];
            }
        }
        else {
            pCount++;
            tmpPrices[pCount] = items[i][0];
            tmpBeauty[pCount] = items[i][1];
        }
    }

    // Perform RMQ
    int nq = queries.length;
    return res;
} } ```
Block decomposition

```java linenums=”1” import java.util.Arrays;

class Solution { public int[] maximumBeauty(int[][] items, int[] queries) { Arrays.sort(items, (a, b) -> Integer.compare(a[0], b[0]));

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
    // get the unique prices and max beauty for each unique price
    int[] tmpPrices = new int[items.length];
    int[] tmpBeauty = new int[items.length];
    tmpPrices[0] = items[0][0];
    tmpBeauty[0] = items[0][1];
    int pCount = 0;
    for (int i = 1; i < items.length; i++ ) {
        if (items[i][0] == tmpPrices[pCount]) {
            if (items[i][1] > tmpBeauty[pCount]) {
                tmpBeauty[pCount] = items[i][1];
            }
        }
        else {
            pCount++;
            tmpPrices[pCount] = items[i][0];
            tmpBeauty[pCount] = items[i][1];
        }
    }
    // refine data
    int[] prices = new int[pCount + 1];
    int[] beauty = new int[pCount + 1];
    for (int i = 0; i < prices.length; i++ ) {
        prices[i] = tmpPrices[i];
        beauty[i] = tmpBeauty[i];
    }

    // block approach
    int n = pCount + 1;
    int b = (int)Math.ceil(Math.sqrt(n));
    int nBlocks = (int)Math.ceil(1.0 * n/b);
    int[] maxBlock = new int[nBlocks];

    // find max at each block
    for (int i = 0; i < nBlocks; i++) {
        int maxBeauty = 0;
        for (int j = 0; j < b; j++) {
            int pos = i * nBlocks + j;
            if (pos >= n) break;
            if (beauty[pos] > maxBeauty)
                maxBeauty = beauty[pos];
        }
        maxBlock[i] = maxBeauty;
    } 

    // Perform RMQ
    int nq = queries.length;
    int[] res = new int[nq];
    for (int i = 0; i < nq; i++) {
        res[i] = 0;
        for (int j = 0; j < n; j++) {
            if (prices[j] > queries[i]) break;
            int bIndex = j / b;
            for (int localB = 0; localB < bIndex; localB++) {
                if (res[i] < maxBlock[localB]) res[i] = maxBlock[localB];
            }
            int maxBlockIndex = (bIndex + 1) * b;
            for (int localB = bIndex * b; localB < maxBlockIndex && localB < n; localB ++) {
                if (prices[localB] > queries[i]) break;
                if (res[i] < beauty[localB]) res[i] = beauty[localB];
            }
        }
    }

    return res;
} } ```

Hybrid Strategies

Hybrid strategies
Runtime analysis
Block decomposition and precomputed table

```java linenums=”1” import java.util.Arrays;

class Solution { public int[] maximumBeauty(int[][] items, int[] queries) { Arrays.sort(items, (a, b) -> Integer.compare(a[0], b[0]));

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
    // get the unique prices and max beauty for each unique price
    int[] tmpPrices = new int[items.length];
    int[] tmpBeauty = new int[items.length];
    tmpPrices[0] = items[0][0];
    tmpBeauty[0] = items[0][1];
    int pCount = 0;
    for (int i = 1; i < items.length; i++ ) {
        if (items[i][0] == tmpPrices[pCount]) {
            if (items[i][1] > tmpBeauty[pCount]) {
                tmpBeauty[pCount] = items[i][1];
            }
        }
        else {
            pCount++;
            tmpPrices[pCount] = items[i][0];
            tmpBeauty[pCount] = items[i][1];
        }
    }
    // refine data
    int[] prices = new int[pCount + 1];
    int[] beauty = new int[pCount + 1];
    for (int i = 0; i < prices.length; i++ ) {
        prices[i] = tmpPrices[i];
        beauty[i] = tmpBeauty[i];
    }

    // block approach
    int n = pCount + 1;
    int b = (int)Math.ceil(Math.sqrt(n));

    int nBlocks = (int)Math.ceil(1.0 * n/b);
    int[] maxBlock = new int[nBlocks];

    // find max at each block
    for (int i = 0; i < nBlocks; i++) {
        int maxBeauty = 0;
        for (int j = 0; j < b; j++) {
            int pos = i * nBlocks + j;
            if (pos >= n) break;
            if (beauty[pos] > maxBeauty)
                maxBeauty = beauty[pos];
        }
        maxBlock[i] = maxBeauty;
    } 

    // Perform RMQ
    int nq = queries.length;
    int[] sorted = queries.clone();
    Arrays.sort(sorted);
    HashMap<Integer, Integer> beautyMap = new HashMap<Integer, Integer>();
    int[] sortedRes = new int[nq];
    int prevMaxIndex = 0;
    int maxPrev = 0;
    for (int i = 0; i < nq; i++) {
        sortedRes[i] = 0;
        for (int j = prevMaxIndex; j < n; j++) {
            if (prices[j] > sorted[i]) {
                prevMaxIndex = j;
                break;
            }
            int bIndex = j / b;
            for (int localB = 0; localB < bIndex; localB++) {
                if (sortedRes[i] < maxBlock[localB]) sortedRes[i] = maxBlock[localB];
            }
            int startLocalIndex = bIndex * b;
            int endLocalIndex = (bIndex + 1) * b;
            for (int localB = startLocalIndex; localB < endLocalIndex && localB < n; localB ++) {
                if (prices[localB] > sorted[i]) break;
                if (sortedRes[i] < beauty[localB]) sortedRes[i] = beauty[localB];
            }
        }
        if (sortedRes[i] < maxPrev) {
            sortedRes[i] = maxPrev;
        } else maxPrev = sortedRes[i];
        beautyMap.put(sorted[i],sortedRes[i]);
    }
    int[] res = new int[nq];
    for (int i = 0; i < nq; i++) {
        res[i] = beautyMap.get(queries[i]);
    }

    return res;
} } ```
Challenge: Implement Sparse Table solution

java linenums="1" // create a HashMap, using a String format for combining // i and j: "i-j" as key // Preprocessing: // for each index i in the range // for each index j starting from i, increment by 1, 2, 4, ..., 2^k // Calculate minimum value using linear method, add to HashMap using "i-j" as key // Queries: // for each index i in queries // Access the minimum values from range [0,2^k-1] and [i - 2^k + 1, i] using the HashMap // Update values in the result queries.

Find the Scope of All Prefixes of an Array

Problem description

Find the Scope of All Prefixes of an Array

Questions

Extras on Block Decomposition

Better but not good enough - as per Dan’s suggestion

```java linenums=”1” import java.util.Arrays;

class Solution { public int[] maximumBeauty(int[][] items, int[] queries) { Arrays.sort(items, (a, b) -> Integer.compare(a[0], b[0]));

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
    // get the unique prices and max beauty for each unique price
    int[] tmpPrices = new int[items.length];
    int[] tmpBeauty = new int[items.length];
    tmpPrices[0] = items[0][0];
    tmpBeauty[0] = items[0][1];
    int pCount = 0;
    for (int i = 1; i < items.length; i++ ) {
        if (items[i][0] == tmpPrices[pCount]) {
            if (items[i][1] > tmpBeauty[pCount]) {
                tmpBeauty[pCount] = items[i][1];
            }
        }
        else {
            pCount++;
            tmpPrices[pCount] = items[i][0];
            tmpBeauty[pCount] = items[i][1];
        }
    }
    // refine data
    int[] prices = new int[pCount + 1];
    int[] beauty = new int[pCount + 1];
    for (int i = 0; i < prices.length; i++ ) {
        prices[i] = tmpPrices[i];
        beauty[i] = tmpBeauty[i];
    }

    // block approach
    int n = pCount + 1;
    int b = (int)Math.ceil(Math.sqrt(n));
    System.out.println("N and B: " + n + " " + b);

    int nBlocks = (int)Math.ceil(1.0 * n/b);
    int[] maxBlock = new int[nBlocks];

    // find max at each block
    int pos = 0;
    for (int i = 0; i < nBlocks; i++) {
        int maxBeauty = 0;
        for (int j = 0; j < b; j++) {
            //int pos = i * nBlocks + j;
            if (pos >= n) break;
            if (beauty[pos] > maxBeauty)
                maxBeauty = beauty[pos];
            //System.out.println(i + "-" + j + " " + pos + "-" + maxBeauty + "-" + beauty[pos]);
            pos++;
        }
        maxBlock[i] = maxBeauty;
    } 

    // Perform RMQ
    int nq = queries.length;
    int[] res = new int[nq];
    for (int i = 0; i < nq; i++) {
        System.out.println("=========");
        res[i] = 0;
        int stopIndex = 0;
        for (int j = 0; j < n; j++) {
            if (prices[j] > queries[i]) {
                break;
            }
            stopIndex = j;
        }

        int bIndex = stopIndex / b;
        for (int localB = 0; localB < bIndex; localB++) {
            if (res[i] < maxBlock[localB]) res[i] = maxBlock[localB];
        }
        int maxBlockIndex = (bIndex + 1) * b;
        for (int localB = bIndex * b; localB <= stopIndex; localB ++) {
            if (prices[localB] > queries[i]) break;
            if (res[i] < beauty[localB]) res[i] = beauty[localB];
        }
    }

    return res;
} } ```
Accepted, but not as good as hybrid

```java linenums=”1” import java.util.Arrays;

class Solution { public int[] maximumBeauty(int[][] items, int[] queries) { Arrays.sort(items, (a, b) -> Integer.compare(a[0], b[0]));

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
    // get the unique prices and max beauty for each unique price
    int[] tmpPrices = new int[items.length];
    int[] tmpBeauty = new int[items.length];
    tmpPrices[0] = items[0][0];
    tmpBeauty[0] = items[0][1];
    int pCount = 0;
    for (int i = 1; i < items.length; i++ ) {
        if (items[i][0] == tmpPrices[pCount]) {
            if (items[i][1] > tmpBeauty[pCount]) {
                tmpBeauty[pCount] = items[i][1];
            }
        }
        else {
            pCount++;
            tmpPrices[pCount] = items[i][0];
            tmpBeauty[pCount] = items[i][1];
        }
    }
    // refine data
    int[] prices = new int[pCount + 1];
    int[] beauty = new int[pCount + 1];
    for (int i = 0; i < prices.length; i++ ) {
        prices[i] = tmpPrices[i];
        beauty[i] = tmpBeauty[i];
    }

    // block approach
    int n = pCount + 1;
    int b = (int)Math.ceil(Math.sqrt(n));
    System.out.println("N and B: " + n + " " + b);

    int nBlocks = (int)Math.ceil(1.0 * n/b);
    int[][] maxBlock = new int[nBlocks][2];

    // find max at each block
    int pos = 0;
    for (int i = 0; i < nBlocks; i++) {
        int maxBeauty = 0;
        int maxPrice = 0;
        for (int j = 0; j < b; j++) {
            if (pos >= n) break;
            if (beauty[pos] > maxBeauty)
                maxBeauty = beauty[pos];
            if (prices[pos] > maxPrice)
                maxPrice = prices[pos];
            pos++;
        }
        maxBlock[i][0] = maxBeauty;
        maxBlock[i][1] = maxPrice;
    } 

    // Perform RMQ
    int nq = queries.length;
    int[] res = new int[nq];
    for (int i = 0; i < nq; i++) {
        System.out.println("=========");
        res[i] = 0;
        int bIndex = nBlocks - 1;
        for (int j = 0; j < nBlocks; j++) {
            if (maxBlock[j][1] > queries[i]) {
                bIndex = j;
                break;
            }
        }
        for (int localB = 0; localB < bIndex; localB++) {
            if (res[i] < maxBlock[localB][0]) res[i] = maxBlock[localB][0];
        }
        int maxBlockIndex = (bIndex + 1) * b;
        for (int localB = bIndex * b; localB <= maxBlockIndex && localB < n; localB ++) {
            if (prices[localB] > queries[i]) break;
            if (res[i] < beauty[localB]) res[i] = beauty[localB];
        }
    }
    return res;
} }      ```