LeetCode-in-Java

3187. Peaks in Array

Hard

A peak in an array arr is an element that is greater than its previous and next element in arr.

You are given an integer array nums and a 2D integer array queries.

You have to process queries of two types:

Return an array answer containing the results of the queries of the first type in order.

Notes:

Example 1:

Input: nums = [3,1,4,2,5], queries = [[2,3,4],[1,0,4]]

Output: [0]

Explanation:

First query: We change nums[3] to 4 and nums becomes [3,1,4,4,5].

Second query: The number of peaks in the [3,1,4,4,5] is 0.

Example 2:

Input: nums = [4,1,4,2,1,5], queries = [[2,2,4],[1,0,2],[1,0,4]]

Output: [0,1]

Explanation:

First query: nums[2] should become 4, but it is already set to 4.

Second query: The number of peaks in the [4,1,4] is 0.

Third query: The second 4 is a peak in the [4,1,4,2,1].

Constraints:

Solution

import java.util.ArrayList;
import java.util.List;

public class Solution {
    public List<Integer> countOfPeaks(int[] nums, int[][] queries) {
        boolean[] peaks = new boolean[nums.length];
        int[] binaryIndexedTree = new int[Integer.highestOneBit(peaks.length) * 2 + 1];
        for (int i = 1; i < peaks.length - 1; ++i) {
            if (nums[i] > Math.max(nums[i - 1], nums[i + 1])) {
                peaks[i] = true;
                update(binaryIndexedTree, i + 1, 1);
            }
        }

        List<Integer> result = new ArrayList<>();
        for (int[] query : queries) {
            if (query[0] == 1) {
                int leftIndex = query[1];
                int rightIndex = query[2];
                result.add(computeRangeSum(binaryIndexedTree, leftIndex + 2, rightIndex));
            } else {
                int index = query[1];
                int value = query[2];
                nums[index] = value;
                for (int i = -1; i <= 1; ++i) {
                    int affected = index + i;
                    if (affected >= 1 && affected <= nums.length - 2) {
                        boolean peak =
                                nums[affected] > Math.max(nums[affected - 1], nums[affected + 1]);
                        if (peak != peaks[affected]) {
                            if (peak) {
                                update(binaryIndexedTree, affected + 1, 1);
                            } else {
                                update(binaryIndexedTree, affected + 1, -1);
                            }
                            peaks[affected] = peak;
                        }
                    }
                }
            }
        }
        return result;
    }

    private int computeRangeSum(int[] binaryIndexedTree, int beginIndex, int endIndex) {
        return (beginIndex <= endIndex)
                ? (query(binaryIndexedTree, endIndex) - query(binaryIndexedTree, beginIndex - 1))
                : 0;
    }

    private int query(int[] binaryIndexedTree, int index) {
        int result = 0;
        while (index != 0) {
            result += binaryIndexedTree[index];
            index -= index & -index;
        }

        return result;
    }

    private void update(int[] binaryIndexedTree, int index, int delta) {
        while (index < binaryIndexedTree.length) {
            binaryIndexedTree[index] += delta;
            index += index & -index;
        }
    }
}