Skip to main content

Command Palette

Search for a command to run...

Range Sum Query - Immutable

The Problem: Too Many Sums, Not Enough Time

Published
5 min readView as Markdown
Range Sum Query - Immutable

Problem Statement

Given an integer array nums, handle multiple queries of the following type:

  1. Calculate the sum of the elements of nums between indices left and right inclusive where left <= right.

Implement the NumArray class:

  • NumArray(int[] nums) Initializes the object with the integer array nums.

  • int sumRange(int left, int right) Returns the sum of the elements of nums between indices left and right inclusive (i.e. nums[left] + nums[left + 1] + ... + nums[right]).

Example :

Example 1:

Input
["NumArray", "sumRange", "sumRange", "sumRange"]
[[[-2, 0, 3, -5, 2, -1]], [0, 2], [2, 5], [0, 5]]
Output
[null, 1, -1, -3]

Explanation
NumArray numArray = new NumArray([-2, 0, 3, -5, 2, -1]);
numArray.sumRange(0, 2); // return (-2) + 0 + 3 = 1
numArray.sumRange(2, 5); // return 3 + (-5) + 2 + (-1) = -1
numArray.sumRange(0, 5); // return (-2) + 0 + 3 + (-5) + 2 + (-1) = -3

Before Coding: Think Like a Human

I will leave this one for you , even if you don’t believe in yourself, I do and you are putting in the work. You just have to trust yourself , understanding the question what is it asking , it will come to you be comfortable in not knowing. step 1 then step 2 etc you got this.

Beginner Approach: Brute Force (Nested Loops)

Alright let’s get into it , we understood the question and now implementation time but Before we get all smart and fancy with clean, idiomatic JavaScript , let’s appreciate the good old brute force approach.

Imagine you’re given nums = [1, 2, 3, 4, 5] and asked, what’s the sum from index 1 to 3?” And naturally, you’re like: “Uh, easy. I’ll just add nums[1] + nums[2] + nums[3].”

class NumArray {
  constructor(nums) {
    this.nums = nums;
  }

  sumRange(left, right) {
    let result = 0;
    for (let i = left; i <= right; i++) {
      result += this.nums[i];
    }
    return result;
  }
}

Time Complexity: O(n).
Space Complexity: O(1) .
Why not use: As soon as the input size goes beyond a few hundred elements, this approach becomes painfully slow. Plus, you deserve better. There’s literally a one-pass O(n) solution. Why suffer?

What Makes It Brute Force? Because you're repeating the same additions every time. There's no memory, no optimization — just raw loops. It works, but it’s inefficient when queries stack up.

Intermediate Approach: Prefix Sum

Let’s take it a step further. This is where you start training your mind to think not just about how to solve the problem, but how to solve it smarter.

Here’s the key mindset shift:

How can I reduce time complexity by avoiding unnecessary addition ?

That’s it. That’s the question that levels you up.

So what’s unnecessary in brute force? Well, adding every single values everytime. We don’t need to do that. What we really need is simple:

Rather than re-adding values every time, precompute a prefix sum array in one pass:

Here’s how it works:

prefixSum[i] = nums[0] + nums[1] + ... + nums[i - 1]
//So, to get the sum from left to right, we do:
prefixSum[right + 1] - prefixSum[left]

That’s it. It’s not magic—it’s just observation and logic. Here’s the beauty in code:

class NumArray {
  constructor(nums) {
    this.prefixSum = [0]; // prefixSum[0] = 0

    for (let i = 0; i < nums.length; i++) {
      this.prefixSum[i + 1] = this.prefixSum[i] + nums[i];
    }
  }
  sumRange(left, right) {
    return this.prefixSum[right + 1] - this.prefixSum[left];
  }
}

Time Complexity: O(n) for setup, O(1) per query.
Space Complexity: O(n) for the prefix sum array.

Advanced Version: Cleaner Code (Same Logic, Just Sleek)

You're here. You’ve cracked the brute force. You’ve grasped the prefix sum technique. Now it’s time to flex your style. Because let’s be honest:

Clean code isn’t just about fewer lines—it’s about clarity, confidence, and control.

We’re still using the same logic: let’s clean it up further using concise style and modern syntax:

What Changed?

    • Uses Array.reduce() to make the prefix sum logic sleek and idiomatic.

      • Super readable, yet performant.
class NumArray {
  constructor(nums) {
    this.prefixSum = nums.reduce((acc, num, i) => {
      acc[i + 1] = acc[i] + num;
      return acc;
    }, [0]);
  }

  sumRange(left, right) {
    return this.prefixSum[right + 1] - this.prefixSum[left];
  }
}

Time Complexity: We’re only going through the list once. O(n).
Space Complexity: No additional space is used aside from variables like max_profit and profitO(1) .

Final Thoughts

Another one in the books. If you’ve made it this far, you're not just solving problems. You're building intuition (Before Coding: Think Like a Human). You’ve done the groundwork Brute force (manual effort). You understand the logic (Brute Force). Made it beautiful Prefix sums (precompute & subtract). Finally, we swap out verbose conditionals with built-in JavaScript functions and structure the loop with clarity and Elegant code (clean and idiomatic).

The Big Lesson?

If you noticed, I didn’t reinvent the wheel at every stage. Instead, I refined the same idea, each time with more efficiency, clarity, and intention. That’s the real journey of a programmer — from “just making it work” to making it clean, fast, and elegant.

Q/A session

What If the array is mutable ?

Boom. Now you're thinking like a next-level developer. Because in that case — spoiler alert — neither brute force nor prefix sums would be enough. You’d need to explore advanced data structures like a Segment Tree or a Binary Indexed Tree (Fenwick Tree). But don't rush there just yet. Master the foundations first. Know when and why to use prefix sums — like we did here. Before you jump into code, ask questions like:

  • What is the problem really asking?

  • Am I repeating unnecessary work?

  • Can I compute once and reuse later?

Every time you slow down to ask why, you build intuition. And intuition? That’s what separates coders from engineers.

You got this. Every bug, every brute force, every small cleanup — it all counts. Keep building. Keep refining. You're not just writing JavaScript. You're writing experience.