|
| 1 | +/* |
| 2 | +Problem Name: Count Distinct Subarrays Divisible by K in Sorted Array |
| 3 | +Problem Link: https://leetcode.com/problems/count-distinct-subarrays-divisible-by-k-in-sorted-array/ |
| 4 | +Platform: LeetCode |
| 5 | +Language: C++ |
| 6 | +Author: Aditya Shimoga |
| 7 | +Date: 30th October 2025 |
| 8 | +
|
| 9 | +Description: |
| 10 | +----------------------------------- |
| 11 | +Given a sorted array nums and an integer k, find the number of distinct subarrays |
| 12 | +whose sum is divisible by k. |
| 13 | +
|
| 14 | +Key Insight: |
| 15 | +----------------------------------- |
| 16 | +- For any subarray [l, r], sum(l..r) is divisible by k ⇔ prefixSum[r] % k == prefixSum[l-1] % k. |
| 17 | +- To count valid subarrays efficiently, we maintain a frequency map of prefix sums modulo k. |
| 18 | +- Since the array is sorted and may contain repeated elements, we process contiguous "blocks" |
| 19 | + of equal numbers separately. This ensures we don’t count identical subarrays multiple times. |
| 20 | +- For each block: |
| 21 | + 1. Calculate all valid subarrays ending in this block using prefix remainders from previous blocks. |
| 22 | + 2. Update the remainder frequency map after processing the block. |
| 23 | +
|
| 24 | +Complexity: |
| 25 | +----------------------------------- |
| 26 | +Time Complexity: O(N) |
| 27 | +Space Complexity: O(K) , depending on distinct remainders |
| 28 | +*/ |
| 29 | + |
| 30 | +#include <bits/stdc++.h> |
| 31 | +using namespace std; |
| 32 | + |
| 33 | +class Solution { |
| 34 | +public: |
| 35 | + long long numGoodSubarrays(vector<int>& nums, int k) { |
| 36 | + long long divisor = 1LL * k; |
| 37 | + long long prefixSum = 0LL, resultCount = 0LL; |
| 38 | + int n = nums.size(); |
| 39 | + |
| 40 | + map<int, int> remainderFreq; // Tracks frequency of prefix sums modulo k |
| 41 | + |
| 42 | + int i = 0; |
| 43 | + while (i < n) { |
| 44 | + int j = i; |
| 45 | + int currentValue = nums[i]; |
| 46 | + long long tempPrefixSum = prefixSum; |
| 47 | + |
| 48 | + // Step 1: Count valid subarrays ending within the current block |
| 49 | + while (j < n && nums[j] == currentValue) { |
| 50 | + prefixSum += nums[j]; |
| 51 | + int remainder = prefixSum % divisor; |
| 52 | + |
| 53 | + // Subarray from start (remainder == 0) |
| 54 | + if (remainder == 0) resultCount++; |
| 55 | + |
| 56 | + // Subarray ending here matches an earlier prefix remainder |
| 57 | + if (remainderFreq.count(remainder)) |
| 58 | + resultCount += 1LL * remainderFreq[remainder]; |
| 59 | + |
| 60 | + j++; |
| 61 | + } |
| 62 | + |
| 63 | + // Step 2: Update frequency map for this block |
| 64 | + j = i; |
| 65 | + while (j < n && nums[j] == currentValue) { |
| 66 | + tempPrefixSum += nums[j]; |
| 67 | + int remainder = tempPrefixSum % divisor; |
| 68 | + remainderFreq[remainder]++; |
| 69 | + j++; |
| 70 | + } |
| 71 | + |
| 72 | + // Move to next distinct value block |
| 73 | + i = j; |
| 74 | + } |
| 75 | + |
| 76 | + return resultCount; |
| 77 | + } |
| 78 | +}; |
| 79 | + |
| 80 | +/* |
| 81 | +Example: |
| 82 | +Input: |
| 83 | +nums = [1,1,2,2,3], k = 3 |
| 84 | +
|
| 85 | +Output: |
| 86 | +Number of distinct subarrays divisible by 3 = 4 |
| 87 | +
|
| 88 | +Explanation: |
| 89 | +Subarrays divisible 3: [3], [1,2], [1,1,2,2],[1,1,2,2,3] |
| 90 | +*/ |
| 91 | + |
| 92 | +int main() { |
| 93 | + Solution solver; |
| 94 | + |
| 95 | + // Test Case 1 |
| 96 | + vector<int> nums1 = {1, 1, 2, 2, 3}; |
| 97 | + int k1 = 3; |
| 98 | + long long result1 = solver.numGoodSubarrays(nums1, k1); |
| 99 | + cout << "Test Case 1:" << endl; |
| 100 | + cout << "Input: nums = [1,1,2,2,3], k = 3" << endl; |
| 101 | + cout << "Output: " << result1 << endl; |
| 102 | + cout << "Expected: 4" << endl << endl; |
| 103 | + |
| 104 | + // Test Case 2 |
| 105 | + vector<int> nums2 = {2, 2, 2, 4, 4}; |
| 106 | + int k2 = 4; |
| 107 | + long long result2 = solver.numGoodSubarrays(nums2, k2); |
| 108 | + cout << "Test Case 2:" << endl; |
| 109 | + cout << "Input: nums = [2,2,2,4,4], k = 4" << endl; |
| 110 | + cout << "Output: " << result2 << endl; |
| 111 | + cout << "Expected: 6" << endl; |
| 112 | + |
| 113 | + return 0; |
| 114 | +} |
0 commit comments