LeetCode #3525 — HARD

Find X Value of Array II

Break down a hard problem into reliable checkpoints, edge-case handling, and complexity trade-offs.

Solve on LeetCode
The Problem

Problem Statement

You are given an array of positive integers nums and a positive integer k. You are also given a 2D array queries, where queries[i] = [indexi, valuei, starti, xi].

You are allowed to perform an operation once on nums, where you can remove any suffix from nums such that nums remains non-empty.

The x-value of nums for a given x is defined as the number of ways to perform this operation so that the product of the remaining elements leaves a remainder of x modulo k.

For each query in queries you need to determine the x-value of nums for xi after performing the following actions:

  • Update nums[indexi] to valuei. Only this step persists for the rest of the queries.
  • Remove the prefix nums[0..(starti - 1)] (where nums[0..(-1)] will be used to represent the empty prefix).

Return an array result of size queries.length where result[i] is the answer for the ith query.

A prefix of an array is a subarray that starts from the beginning of the array and extends to any point within it.

A suffix of an array is a subarray that starts at any point within the array and extends to the end of the array.

Note that the prefix and suffix to be chosen for the operation can be empty.

Note that x-value has a different definition in this version.

Example 1:

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

Output: [2,2,2]

Explanation:

  • For query 0, nums becomes [1, 2, 2, 4, 5], and the empty prefix must be removed. The possible operations are:
    • Remove the suffix [2, 4, 5]. nums becomes [1, 2].
    • Remove the empty suffix. nums becomes [1, 2, 2, 4, 5] with a product 80, which gives remainder 2 when divided by 3.
  • For query 1, nums becomes [1, 2, 2, 3, 5], and the prefix [1, 2, 2] must be removed. The possible operations are:
    • Remove the empty suffix. nums becomes [3, 5].
    • Remove the suffix [5]. nums becomes [3].
  • For query 2, nums becomes [1, 2, 2, 3, 5], and the empty prefix must be removed. The possible operations are:
    • Remove the suffix [2, 2, 3, 5]. nums becomes [1].
    • Remove the suffix [3, 5]. nums becomes [1, 2, 2].

Example 2:

Input: nums = [1,2,4,8,16,32], k = 4, queries = [[0,2,0,2],[0,2,0,1]]

Output: [1,0]

Explanation:

  • For query 0, nums becomes [2, 2, 4, 8, 16, 32]. The only possible operation is:
    • Remove the suffix [2, 4, 8, 16, 32].
  • For query 1, nums becomes [2, 2, 4, 8, 16, 32]. There is no possible way to perform the operation.

Example 3:

Input: nums = [1,1,2,1,1], k = 2, queries = [[2,1,0,1]]

Output: [5]

Constraints:

  • 1 <= nums[i] <= 109
  • 1 <= nums.length <= 105
  • 1 <= k <= 5
  • 1 <= queries.length <= 2 * 104
  • queries[i] == [indexi, valuei, starti, xi]
  • 0 <= indexi <= nums.length - 1
  • 1 <= valuei <= 109
  • 0 <= starti <= nums.length - 1
  • 0 <= xi <= k - 1
Patterns Used

Roadmap

  1. Brute Force Baseline
  2. Core Insight
  3. Algorithm Walkthrough
  4. Edge Cases
  5. Full Annotated Code
  6. Interactive Study Demo
  7. Complexity Analysis
Step 01

Brute Force Baseline

Problem summary: You are given an array of positive integers nums and a positive integer k. You are also given a 2D array queries, where queries[i] = [indexi, valuei, starti, xi]. You are allowed to perform an operation once on nums, where you can remove any suffix from nums such that nums remains non-empty. The x-value of nums for a given x is defined as the number of ways to perform this operation so that the product of the remaining elements leaves a remainder of x modulo k. For each query in queries you need to determine the x-value of nums for xi after performing the following actions: Update nums[indexi] to valuei. Only this step persists for the rest of the queries. Remove the prefix nums[0..(starti - 1)] (where nums[0..(-1)] will be used to represent the empty prefix). Return an array result of size queries.length where result[i] is the answer for the ith query. A prefix of an array is a

Baseline thinking

Start with the most direct exhaustive search. That gives a correctness anchor before optimizing.

Pattern signal: Array · Math · Segment Tree

Example 1

[1,2,3,4,5]
3
[[2,2,0,2],[3,3,3,0],[0,1,0,1]]

Example 2

[1,2,4,8,16,32]
4
[[0,2,0,2],[0,2,0,1]]

Example 3

[1,1,2,1,1]
2
[[2,1,0,1]]

Related Problems

  • Longest Uploaded Prefix (longest-uploaded-prefix)
  • Minimum Sum of Values by Dividing Array (minimum-sum-of-values-by-dividing-array)
Step 02

Core Insight

What unlocks the optimal approach

  • Use a segment tree to efficiently maintain and merge product prefix information for the array <code>nums</code>.
  • In each segment tree node, store a frequency count of prefix product remainders for every <code>x</code> in the range [0, k - 1].
  • For each query, update <code>nums[index]</code> to <code>value</code>, then merge the segments corresponding to <code>nums[start..n - 1]</code> to compute the <code>x-value</code> for <code>xi</code>.
Interview move: turn each hint into an invariant you can check after every iteration/recursion step.
Step 03

Algorithm Walkthrough

Iteration Checklist

  1. Define state (indices, window, stack, map, DP cell, or recursion frame).
  2. Apply one transition step and update the invariant.
  3. Record answer candidate when condition is met.
  4. Continue until all input is consumed.
Use the first example testcase as your mental trace to verify each transition.
Step 04

Edge Cases

Minimum Input
Single element / shortest valid input
Validate boundary behavior before entering the main loop or recursion.
Duplicates & Repeats
Repeated values / repeated states
Decide whether duplicates should be merged, skipped, or counted explicitly.
Extreme Constraints
Largest constraint values
Re-check complexity target against constraints to avoid time-limit issues.
Invalid / Corner Shape
Empty collections, zeros, or disconnected structures
Handle special-case structure before the core algorithm path.
Step 05

Full Annotated Code

Source-backed implementations are provided below for direct study and interview prep.

// Accepted solution for LeetCode #3525: Find X Value of Array II
// Auto-generated Java example from go.
class Solution {
    public void exampleSolution() {
    }
}
// Reference (go):
// // Accepted solution for LeetCode #3525: Find X Value of Array II
// package main
// 
// import (
// 	"math/bits"
// )
// 
// // https://space.bilibili.com/206214
// var k int
// 
// type data struct {
// 	mul int
// 	cnt [5]int
// }
// 
// type seg []data
// 
// func mergeData(a, b data) data {
// 	cnt := a.cnt
// 	for rx, c := range b.cnt {
// 		cnt[a.mul*rx%k] += c
// 	}
// 	return data{a.mul * b.mul % k, cnt}
// }
// 
// func newData(val int) data {
// 	mul := val % k
// 	cnt := [5]int{}
// 	cnt[mul] = 1
// 	return data{mul, cnt}
// }
// 
// func (t seg) maintain(o int) {
// 	t[o] = mergeData(t[o<<1], t[o<<1|1])
// }
// 
// func (t seg) build(a []int, o, l, r int) {
// 	if l == r {
// 		t[o] = newData(a[l])
// 		return
// 	}
// 	m := (l + r) >> 1
// 	t.build(a, o<<1, l, m)
// 	t.build(a, o<<1|1, m+1, r)
// 	t.maintain(o)
// }
// 
// func (t seg) update(o, l, r, i, val int) {
// 	if l == r {
// 		t[o] = newData(val)
// 		return
// 	}
// 	m := (l + r) >> 1
// 	if i <= m {
// 		t.update(o<<1, l, m, i, val)
// 	} else {
// 		t.update(o<<1|1, m+1, r, i, val)
// 	}
// 	t.maintain(o)
// }
// 
// func (t seg) query(o, l, r, ql, qr int) data {
// 	if ql <= l && r <= qr {
// 		return t[o]
// 	}
// 	m := (l + r) / 2
// 	if qr <= m {
// 		return t.query(o*2, l, m, ql, qr)
// 	}
// 	if ql > m {
// 		return t.query(o*2+1, m+1, r, ql, qr)
// 	}
// 	lRes := t.query(o*2, l, m, ql, qr)
// 	rRes := t.query(o*2+1, m+1, r, ql, qr)
// 	return mergeData(lRes, rRes)
// }
// 
// func newSegmentTreeWithArray(a []int) seg {
// 	n := len(a)
// 	t := make(seg, 2<<bits.Len(uint(n-1)))
// 	t.build(a, 1, 0, n-1)
// 	return t
// }
// 
// func resultArray(nums []int, K int, queries [][]int) []int {
// 	k = K
// 	t := newSegmentTreeWithArray(nums)
// 	n := len(nums)
// 	ans := make([]int, len(queries))
// 	for qi, q := range queries {
// 		t.update(1, 0, n-1, q[0], q[1])
// 		res := t.query(1, 0, n-1, q[2], n-1)
// 		ans[qi] = res.cnt[q[3]]
// 	}
// 	return ans
// }
Step 06

Interactive Study Demo

Use this to step through a reusable interview workflow for this problem.

Press Step or Run All to begin.
Step 07

Complexity Analysis

Time
O(n + q log n)
Space
O(n)

Approach Breakdown

BRUTE FORCE
O(n × q) time
O(1) space

For each of q queries, scan the entire range to compute the aggregate (sum, min, max). Each range scan takes up to O(n) for a full-array query. With q queries: O(n × q) total. Point updates are O(1) but queries dominate.

SEGMENT TREE
O(n + q log n) time
O(n) space

Building the tree is O(n). Each query or update traverses O(log n) nodes (tree height). For q queries: O(n + q log n) total. Space is O(4n) ≈ O(n) for the tree array. Lazy propagation adds O(1) per node for deferred updates.

Shortcut: Build O(n), query/update O(log n) each. When you need both range queries AND point updates.
Coach Notes

Common Mistakes

Review these before coding to avoid predictable interview regressions.

Off-by-one on range boundaries

Wrong move: Loop endpoints miss first/last candidate.

Usually fails on: Fails on minimal arrays and exact-boundary answers.

Fix: Re-derive loops from inclusive/exclusive ranges before coding.

Overflow in intermediate arithmetic

Wrong move: Temporary multiplications exceed integer bounds.

Usually fails on: Large inputs wrap around unexpectedly.

Fix: Use wider types, modular arithmetic, or rearranged operations.