Sum of Good Numbers
EasyPrompt
Given an array of integers nums and an integer k, an element nums[i] is considered good if it is strictly greater than the elements at indices i - k and i + k (if those indices exist). If neither of these indices exists, nums[i] is still considered good.
Return the sum of all the good elements in the array.
Example 1:
Input: nums = [1,3,2,1,5,4], k = 2
Output: 12
Explanation:
The good numbers are nums[1] = 3, nums[4] = 5, and nums[5] = 4 because they are strictly greater than the numbers at indices i - k and i + k.
Example 2:
Input: nums = [2,1], k = 1
Output: 2
Explanation:
The only good number is nums[0] = 2 because it is strictly greater than nums[1].
Constraints:
2 <= nums.length <= 1001 <= nums[i] <= 10001 <= k <= floor(nums.length / 2)
Approaches
2 approaches with complexity analysis and trade-offs.
This approach is a deliberately inefficient, brute-force method designed to highlight the importance of direct index access. Instead of directly calculating and accessing nums[i-k] and nums[i+k], it simulates this by creating copies of the subarrays to the left and right of the current element. This is a highly inefficient way to access elements that are at a known offset and is used here to demonstrate a non-optimal solution.
Algorithm
-
- Initialize a variable
sumto 0.
- Initialize a variable
-
- Loop through the array
numsfromi = 0tonums.length - 1.
- Loop through the array
-
- For each element
nums[i], assume it is a good number by setting a flag, e.g.,boolean isGood = true;.
- For each element
-
- Check the left neighbor: If the index
i - kis valid (>= 0), create a temporary arrayleftPartby copying elements fromnums[0]tonums[i-1]. Then, comparenums[i]withleftPart[i-k]. Ifnums[i]is not strictly greater, setisGoodtofalse.
- Check the left neighbor: If the index
-
- Check the right neighbor: If
isGoodis still true and the indexi + kis valid (< nums.length), create another temporary arrayrightPartby copying elements fromnums[i+1]to the end of the array. Comparenums[i]withrightPart[k-1]. Ifnums[i]is not strictly greater, setisGoodtofalse.
- Check the right neighbor: If
-
- If the
isGoodflag remainstrueafter both checks, addnums[i]to thesum.
- If the
-
- After the loop finishes, return the total
sum.
- After the loop finishes, return the total
Walkthrough
The algorithm iterates through each element nums[i] of the array.
To check the left neighbor nums[i-k], it first verifies if the index i-k is valid. If so, it creates a new array containing all elements to the left of i using a method like Arrays.copyOfRange(nums, 0, i). Then it accesses the element at index i-k from this new array to perform the comparison.
Similarly, to check the right neighbor nums[i+k], it creates a copy of the subarray to the right of i and accesses the required element at the adjusted index k-1.
This process of creating array copies inside a loop is computationally expensive. Copying an array of size M takes O(M) time. Since this is done for each of the N elements in the input array, the overall time complexity becomes quadratic.
import java.util.Arrays; class Solution { public int sumOfGoodNumbers(int[] nums, int k) { int n = nums.length; long sum = 0; for (int i = 0; i < n; i++) { boolean isGood = true; // Inefficiently check left neighbor via array copy if (i - k >= 0) { // This copy operation is expensive if (nums[i] <= nums[i - k]) { isGood = false; } } // Inefficiently check right neighbor via array copy if (isGood && i + k < n) { // Index in the right part is k-1 if (nums[i] <= nums[i + k]) { isGood = false; } } if (isGood) { sum += nums[i]; } } return (int) sum; }}Complexity
Time
O(N^2), where N is the number of elements in `nums`. The main loop runs N times. Inside the loop, creating a copy of a part of the array can take up to O(N) time. This results in a nested, quadratic time complexity.
Space
O(N), where N is the number of elements in `nums`. In each iteration of the loop, a new array of size up to N-1 can be created, leading to linear space complexity.
Trade-offs
Pros
It correctly solves the problem.
The logic is broken down into distinct steps for checking each neighbor, which might be simple to conceptualize for a beginner.
Cons
Very poor time complexity of O(N^2), making it unsuitable for large inputs.
High space complexity of O(N) due to the creation of temporary arrays in each iteration.
Overly complicated and inefficient for a problem that can be solved with simple index access.
This is the most efficient and straightforward approach. It involves a single pass through the array. For each element, it directly accesses its neighbors at i-k and i+k (if they exist) using their calculated indices and performs the required comparisons. This avoids any redundant computations or inefficient data access patterns.
Algorithm
-
- Initialize a variable
sumto 0.
- Initialize a variable
-
- Get the length of the array,
n = nums.length.
- Get the length of the array,
-
- Loop through the array
numsfrom indexi = 0ton - 1.
- Loop through the array
-
- For each
nums[i], assume it's a good number by initializing a boolean flag,isGood = true.
- For each
-
- Check left condition: If the index
i - kis valid (i.e.,i - k >= 0), check ifnums[i] <= nums[i - k]. If it is, the number is not good, so setisGood = false.
- Check left condition: If the index
-
- Check right condition: If
isGoodis still true and the indexi + kis valid (i.e.,i + k < n), check ifnums[i] <= nums[i + k]. If it is, setisGood = false.
- Check right condition: If
-
- If the
isGoodflag is stilltrueafter these checks, it meansnums[i]is a good number. Addnums[i]tosum.
- If the
-
- After the loop completes, return the final
sum.
- After the loop completes, return the final
Walkthrough
The algorithm initializes a sum to zero and iterates through the input array nums from the first element to the last. In each iteration, for the current element nums[i], it checks two conditions to determine if it's a "good" number.
-
Left Condition: It first checks if the index
i - kis within the array bounds (i.e.,i - k >= 0). If it is, it comparesnums[i]withnums[i - k]. Ifnums[i]is not strictly greater, the element is not good. If the indexi - kis out of bounds, this condition is automatically met. -
Right Condition: Similarly, it checks if the index
i + kis within bounds (i.e.,i + k < nums.length). If it is, it comparesnums[i]withnums[i + k]. Ifnums[i]is not strictly greater, the element is not good. If the indexi + kis out of bounds, this condition is also automatically met.
An element nums[i] is considered "good" only if it satisfies both the left and right conditions. If an element is determined to be good, its value is added to a running total. After iterating through all the elements, the final sum is returned.
class Solution { public int sumOfGoodNumbers(int[] nums, int k) { int n = nums.length; long sum = 0; for (int i = 0; i < n; i++) { boolean isGood = true; // Check left neighbor if (i - k >= 0) { if (nums[i] <= nums[i - k]) { isGood = false; } } // Check right neighbor only if left condition is still met if (isGood && i + k < n) { if (nums[i] <= nums[i + k]) { isGood = false; } } if (isGood) { sum += nums[i]; } } return (int) sum; }}Complexity
Time
O(N), where N is the length of `nums`. We iterate through the array once, and all operations inside the loop (index calculations, comparisons) take constant time, O(1).
Space
O(1). We only use a constant amount of extra space for variables like `sum`, `n`, and the loop counter, regardless of the input size.
Trade-offs
Pros
Optimal time complexity, as we must examine each element at least once.
Minimal space usage, making it very memory-efficient.
The logic is simple, direct, and easy to understand and implement.
Cons
There are no significant cons to this approach as it is optimal in terms of time and space complexity.
Solutions
Solution
class Solution {public int sumOfGoodNumbers(int[] nums, int k) { int ans = 0; int n = nums.length; for (int i = 0; i < n; ++i) { if (i >= k && nums[i] <= nums[i - k]) { continue; } if (i + k < n && nums[i] <= nums[i + k]) { continue; } ans += nums[i]; } return ans; }}class Solution {public: int sumOfGoodNumbers(vector<int> &nums, int k) { int ans = 0; int n = nums.size(); for (int i = 0; i < n; ++i) { if (i >= k && nums[i] <= nums[i - k]) { continue; } if (i + k < n && nums[i] <= nums[i + k]) { continue; } ans += nums[i]; } return ans; }};class Solution: def sumOfGoodNumbers(self, nums: List[int], k: int) -> int: ans = 0 for i, x in enumerate(nums): if i >= k and x <= nums[i - k]: continue if i + k < len(nums) and x <= nums[i + k]: continue ans += x return ansVideo walkthrough
Newsletter
One sharp idea, every week
System design and interview prep — short enough to finish.
No spam. Unsubscribe anytime.
Practice
Same difficulty — related problems to reinforce the pattern.