Skip to content

3187. Peaks in Array 👍

Approach 1: Fenwick Tree

  • Time: $O(n\log n + q\log n)$
  • Space: $O(n + q)$
 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
class FenwickTree {
 public:
  FenwickTree(int n) : sums(n + 1) {}

  void add(int i, int delta) {
    while (i < sums.size()) {
      sums[i] += delta;
      i += lowbit(i);
    }
  }

  int get(int i) const {
    int sum = 0;
    while (i > 0) {
      sum += sums[i];
      i -= lowbit(i);
    }
    return sum;
  }

 private:
  vector<int> sums;

  static inline int lowbit(int i) {
    return i & -i;
  }
};

class Solution {
 public:
  vector<int> countOfPeaks(vector<int>& nums, vector<vector<int>>& queries) {
    vector<int> ans;
    vector<int> peak = getPeak(nums);
    FenwickTree tree(peak.size());

    for (int i = 0; i < peak.size(); ++i)
      tree.add(i + 1, peak[i]);

    // Update the peak array and Fenwick tree if the peak status of nums[i]
    // changes.
    auto update = [&](int i) {
      const int newPeak = isPeak(nums, i);
      if (newPeak != peak[i]) {
        tree.add(i + 1, newPeak - peak[i]);
        peak[i] = newPeak;
      }
    };

    for (const vector<int>& query : queries)
      if (query[0] == 1) {
        const int l = query[1];
        const int r = query[2];
        ans.push_back(r - l < 2 ? 0 : tree.get(r) - tree.get(l + 1));
      } else if (query[0] == 2) {
        const int index = query[1];
        const int val = query[2];
        nums[index] = val;
        update(index);
        if (index > 0)
          update(index - 1);
        if (index + 1 < nums.size())
          update(index + 1);
      }

    return ans;
  }

 private:
  vector<int> getPeak(const vector<int>& nums) {
    vector<int> peak(nums.size());
    for (int i = 1; i + 1 < nums.size(); ++i)
      peak[i] = nums[i] > nums[i - 1] && nums[i] > nums[i + 1];
    return peak;
  }

  bool isPeak(const vector<int>& nums, int i) {
    return i > 0 && i + 1 < nums.size() && nums[i] > nums[i - 1] &&
           nums[i] > nums[i + 1];
  }
};
 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
class FenwickTree {
  public FenwickTree(int n) {
    sums = new int[n + 1];
  }

  public void add(int i, int delta) {
    while (i < sums.length) {
      sums[i] += delta;
      i += lowbit(i);
    }
  }

  public int get(int i) {
    int sum = 0;
    while (i > 0) {
      sum += sums[i];
      i -= lowbit(i);
    }
    return sum;
  }

  private int[] sums;

  private static int lowbit(int i) {
    return i & -i;
  }
}

class Solution {
  public List<Integer> countOfPeaks(int[] nums, int[][] queries) {
    List<Integer> ans = new ArrayList<>();
    int[] peak = getPeak(nums);
    FenwickTree tree = new FenwickTree(peak.length);

    for (int i = 0; i < peak.length; ++i)
      tree.add(i + 1, peak[i]);

    // Update the peak array and Fenwick tree if the peak status of nums[i]
    // changes.
    for (int[] query : queries) {
      if (query[0] == 1) {
        final int l = query[1];
        final int r = query[2];
        ans.add(r - l < 2 ? 0 : tree.get(r) - tree.get(l + 1));
      } else if (query[0] == 2) {
        final int index = query[1];
        final int val = query[2];
        nums[index] = val;
        update(nums, peak, tree, index);
        if (index > 0)
          update(nums, peak, tree, index - 1);
        if (index + 1 < nums.length)
          update(nums, peak, tree, index + 1);
      }
    }

    return ans;
  }

  private void update(int[] nums, int[] peak, FenwickTree tree, int i) {
    final int newPeak = isPeak(nums, i) ? 1 : 0;
    if (newPeak != peak[i]) {
      tree.add(i + 1, newPeak - peak[i]);
      peak[i] = newPeak;
    }
  }

  private int[] getPeak(int[] nums) {
    int[] peak = new int[nums.length];
    for (int i = 1; i + 1 < nums.length; i++)
      peak[i] = nums[i] > nums[i - 1] && nums[i] > nums[i + 1] ? 1 : 0;
    return peak;
  }

  private boolean isPeak(int[] nums, int i) {
    return i > 0 && i + 1 < nums.length && nums[i] > nums[i - 1] && nums[i] > nums[i + 1];
  }
}
 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
class FenwickTree:
  def __init__(self, n: int):
    self.sums = [0] * (n + 1)

  def add(self, i: int, delta: int) -> None:
    while i < len(self.sums):
      self.sums[i] += delta
      i += FenwickTree.lowbit(i)

  def get(self, i: int) -> int:
    summ = 0
    while i > 0:
      summ += self.sums[i]
      i -= FenwickTree.lowbit(i)
    return summ

  @staticmethod
  def lowbit(i: int) -> int:
    return i & -i


class Solution:
  def countOfPeaks(
      self,
      nums: list[int],
      queries:
      list[list[int]],
  ) -> list[int]:
    ans = []
    peak = [0] + [int(a < b > c)
                  for a, b, c in zip(nums[:-2], nums[1:-1], nums[2:])] + [0]
    tree = FenwickTree(len(peak))

    for i, p in enumerate(peak):
      tree.add(i + 1, p)

    def update(i: int) -> None:
      """
      Update the peak array and Fenwick tree if the peak status of nums[i]
      changes.
      """
      newPeak = self._isPeak(nums, i)
      if newPeak != peak[i]:
        tree.add(i + 1, newPeak - peak[i])
        peak[i] = newPeak

    for query in queries:
      if query[0] == 1:
        l = query[1]
        r = query[2]
        ans.append(0 if r - l < 2 else tree.get(r) - tree.get(l + 1))
      elif query[0] == 2:
        index = query[1]
        val = query[2]
        nums[index] = val
        update(index)
        if index > 0:
          update(index - 1)
        if index + 1 < len(nums):
          update(index + 1)

    return ans

  def _isPeak(self, nums: list[int], i: int) -> bool:
    return i > 0 and i + 1 < len(nums) and nums[i - 1] < nums[i] > nums[i + 1]

Approach 2: Segment Tree w/ tree array

  • Time: $O(n\log n + q\log n)$
  • Space: $O(n + q)$
 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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
class SegmentTree {
 public:
  explicit SegmentTree(const vector<int>& peak) : n(peak.size()), tree(n * 4) {
    build(peak, 0, 0, n - 1);
  }

  // Updates peak[i] to val.
  void update(int i, int val) {
    update(0, 0, n - 1, i, val);
  }

  // Returns sum(peak[i..j]).
  int query(int i, int j) const {
    return query(0, 0, n - 1, i, j);
  }

 private:
  const int n;       // the size of the input array
  vector<int> tree;  // the segment tree

  void build(const vector<int>& peak, int treeIndex, int lo, int hi) {
    if (lo == hi) {
      tree[treeIndex] = peak[lo];
      return;
    }
    const int mid = (lo + hi) / 2;
    build(peak, 2 * treeIndex + 1, lo, mid);
    build(peak, 2 * treeIndex + 2, mid + 1, hi);
    tree[treeIndex] = merge(tree[2 * treeIndex + 1], tree[2 * treeIndex + 2]);
  }

  void update(int treeIndex, int lo, int hi, int i, int val) {
    if (lo == hi) {
      tree[treeIndex] = val;
      return;
    }
    const int mid = (lo + hi) / 2;
    if (i <= mid)
      update(2 * treeIndex + 1, lo, mid, i, val);
    else
      update(2 * treeIndex + 2, mid + 1, hi, i, val);
    tree[treeIndex] = merge(tree[2 * treeIndex + 1], tree[2 * treeIndex + 2]);
  }

  int query(int treeIndex, int lo, int hi, int i, int j) const {
    if (i <= lo && hi <= j)  // [lo, hi] lies completely inside [i, j].
      return tree[treeIndex];
    if (j < lo || hi < i)  // [lo, hi] lies completely outside [i, j].
      return 0;
    const int mid = (lo + hi) / 2;
    return merge(query(treeIndex * 2 + 1, lo, mid, i, j),
                 query(treeIndex * 2 + 2, mid + 1, hi, i, j));
  }

  int merge(int left, int right) const {
    return left + right;
  }
};

class Solution {
 public:
  vector<int> countOfPeaks(vector<int>& nums, vector<vector<int>>& queries) {
    const vector<int> peak = getPeak(nums);
    vector<int> ans;
    SegmentTree tree(peak);

    for (const vector<int>& query : queries)
      if (query[0] == 1) {
        const int l = query[1];
        const int r = query[2];
        ans.push_back(tree.query(l + 1, r - 1));
      } else if (query[0] == 2) {
        const int index = query[1];
        const int val = query[2];
        nums[index] = val;
        tree.update(index, isPeak(nums, index));
        if (index > 0)
          tree.update(index - 1, isPeak(nums, index - 1));
        if (index + 1 < nums.size())
          tree.update(index + 1, isPeak(nums, index + 1));
      }

    return ans;
  }

 private:
  vector<int> getPeak(const vector<int>& nums) {
    vector<int> peak(nums.size());
    for (int i = 1; i + 1 < nums.size(); ++i)
      peak[i] = nums[i] > nums[i - 1] && nums[i] > nums[i + 1];
    return peak;
  }

  bool isPeak(const vector<int>& nums, int i) {
    return i > 0 && i + 1 < nums.size() && nums[i] > nums[i - 1] &&
           nums[i] > nums[i + 1];
  }
};