Peaks in Array - Complete Solution Guide
Peaks in Array is LeetCode problem 3187, a Hard level challenge. This complete guide provides step-by-step explanations, multiple solution approaches, and optimized code in python3, java, cpp, c.
Problem Statement
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: queries[i] = [1, l i , r i ] , determine the count of peak elements in the subarray nums[l i ..r i ] . queries[i] = [2, index i , val i ] , change nums[index i ] to val i . Return an array answer containing the results of the queries of the first type in order. Notes: The first and the last
Detailed Explanation
The problem requires us to process two types of queries on an integer array `nums`. Type 1 queries ask for the number of 'peak' elements within a specified range `[l, r]` of the array. A peak element is defined as an element that is strictly greater than its adjacent elements. Type 2 queries update an element at a given index with a new value. The goal is to return a list containing the results of all Type 1 queries in the order they appear.
Solution Approach
The solution uses a Fenwick Tree (Binary Indexed Tree) to maintain a count of peak elements. Initially, the Fenwick Tree is populated by iterating through the array and identifying peak elements. When a Type 1 query is encountered, the Fenwick Tree is used to efficiently calculate the number of peaks within the specified range. When a Type 2 query is encountered, the element at the given index is updated. Before updating, the peak status of the index and its immediate neighbors is checked. If any of these positions were a peak, their corresponding values are decremented in the Fenwick Tree. After the update, the peak status of the affected indices are re-evaluated, and their corresponding values are incremented in the Fenwick Tree if they are now a peak.
Step-by-Step Algorithm
- Step 1: Initialize a Fenwick Tree (BIT) with the same size as the input array `nums`.
- Step 2: Iterate through the `nums` array from index 1 to n-2 (exclusive) to identify initial peak elements. If an element is a peak, update the corresponding index in the Fenwick Tree by adding 1.
- Step 3: Iterate through the `queries` array. For each query, check the query type.
- Step 4: If the query type is 1 (range query), extract the left and right indices `l` and `r`. Use the Fenwick Tree to calculate the sum of peaks in the range `[l+1, r-1]`. Append this count to the result list.
- Step 5: If the query type is 2 (update query), extract the index `idx` and the new value `val`. Before updating nums[idx], find all affected positions (idx-1, idx, idx+1) which might be peaks, and remove their contribution from the BIT if they are peaks.
- Step 6: Update `nums[idx]` with `val`.
- Step 7: After updating nums[idx], find all affected positions (idx-1, idx, idx+1) which might become peaks after updating nums[idx], and add their contribution to the BIT if they are peaks.
- Step 8: Append the result list after processing all queries.
Key Insights
- Insight 1: Recognize that brute force counting of peaks for each query can lead to Time Limit Exceeded (TLE).
- Insight 2: Use a Fenwick Tree (Binary Indexed Tree) to efficiently count peaks within a range, enabling updates in logarithmic time.
- Insight 3: Identify that modifying an element affects only the peak status of itself and its immediate neighbors. Only update the BIT for these affected indices.
Complexity Analysis
Time Complexity: O(m*log(n) + n*log(n))
Space Complexity: O(n)
Topics
This problem involves: Array, Binary Indexed Tree, Segment Tree.
Companies
Asked at: Siemens.