|
| 1 | +# 🔥 3 FAST Approaches 🔥 || Simple Fast and Easy || with Explanation |
| 2 | + |
| 3 | +## Approach |
| 4 | + |
| 5 | +When it comes to Sum of Sub-array, the use of Prefix Sum is especially important. |
| 6 | + |
| 7 | +Prefix Sum is the sum of the current integer with the previous integer in the array (Prefix). |
| 8 | + |
| 9 | +Example: nums = [1,2,3,4,5] has the prefix sum array of prefixSum = [1,3,6,10,15], where the nums[0] + 1 = 1, nums[1] + nums[0] = 2 + 1 = 3, nums[2] + nums[1] = 3 + 3 = 6, and so on. |
| 10 | + |
| 11 | +Using the example above, we can determine the sub-array sum of any sub-array using prefix sum. |
| 12 | + |
| 13 | +To get the sub-array sum of nums[2] to nums[4] == 3 + 4 + 5 == 12, we can get from prefixSum[5] - prefixSum[1] == 15 - 3 == 12. |
| 14 | + |
| 15 | +With Prefix Sum, we can evaluate if any sub-array sum is divisible by 'k', if two prefix sums have the same remainder of 'k'. |
| 16 | + |
| 17 | +For Example, nums = [4,2,3], k = 5, with two prefix sum, 4 [4] and 9 [4,2,3]. |
| 18 | + |
| 19 | +Both remainders are 4, with the sub-array between the prefix sum 9 [4,2,3] - 4 [4] == 5 [2,3], which is divisible by 5. |
| 20 | + |
| 21 | +Prefix Sum & Hash Table |
| 22 | + |
| 23 | +## Complexity |
| 24 | + |
| 25 | +### Time Complexity: O(n) |
| 26 | + |
| 27 | +where 'n' is the length of 'nums'. |
| 28 | +In fact, in actual is '2n' as we traverse 'nums' once and the HashMap once, with the worst time complexity of the HashMap being 'n'. |
| 29 | + |
| 30 | +### Space Complexity: O(n) |
| 31 | + |
| 32 | +where 'n' is the length of 'nums'. |
| 33 | +The worst case is when all the prefix sums in 'nums' have different remainders with 'k', resulting in the maximum size of the HashMap to be 'n'. |
| 34 | + |
| 35 | +## Code |
| 36 | + |
| 37 | +```dart |
| 38 | +class Solution { |
| 39 | + int subarraysDivByK(List<int> nums, int k) { |
| 40 | + // Use the HashMap to record the frequency of all the prefix sum remainders. |
| 41 | + HashMap<int, int> map = HashMap(); |
| 42 | + // Note that the integer in 'nums' can be negative. |
| 43 | + // Thus, we need to adjust the negative remainder to positive remainder. |
| 44 | + // Below accounts for both negative and positive remainders. |
| 45 | + // We can also check if the remainder is negative, then add a 'k' to make the remainder positive. |
| 46 | + // For Example, nums = [-2,3,2], k = 5, |
| 47 | + // remainder for the prefix sum of [-2,1,3] are -2, 1 and 3 respectively. |
| 48 | + // We know that [3,2] sum to 5, which is divisible by 5. |
| 49 | + // After converting -2 to 3, by adding 5, it has the same remainder with prefix sum 3. |
| 50 | + for (int i = 0, remainder; i < nums.length; i++) { |
| 51 | + if (i > 0) nums[i] += nums[i - 1]; |
| 52 | + remainder = (nums[i] % k + k) % k; |
| 53 | + map[remainder] = (map[remainder] ?? 0) + 1; |
| 54 | + } |
| 55 | + // The result contains all the prefix sum with remainder 0, |
| 56 | + // as all the prefix sum with remainder of 0 is itself divisible by 'k'. |
| 57 | + // However, do note that the prefix sum with remainder 0 also able to form sub-array sums that is divisible by 'k' |
| 58 | + // with one another, which will be calculated next. |
| 59 | + // For Example: nums = [5,5,5,5], k = 5, |
| 60 | + // The prefix sum of [5,10,15,20] are themselves divisible by 5, while also forming sub-array sums divisible by 5 |
| 61 | + // with 10 [5,5] - 5 [5] == 5, 15 [5,5,5] - 5 [5] == 10, etc. |
| 62 | + int result = (map[0] ?? 0); |
| 63 | + // The prefix sums with the same remainder can form sub-array sums that is divisible by 'k' with each other. |
| 64 | + // For each remainder, the number of sub-array that is divisible by 'k' is the number of combinations from the frequency. |
| 65 | + // Equation for the number of combinations of n items is n * "(n - 1) / 2". |
| 66 | + for (int frequency in map.values) |
| 67 | + result += frequency * (frequency - 1) ~/ 2; |
| 68 | + return result; |
| 69 | + } |
| 70 | +} |
| 71 | +``` |
| 72 | + |
| 73 | +## Prefix Sum & Counting |
| 74 | + |
| 75 | +## Complexity |
| 76 | + |
| 77 | +### Time Complexity: O(n + k) |
| 78 | + |
| 79 | +where 'n' is the length of 'nums'. |
| 80 | +We traverse 'nums' once and the counting array of size 'k' once. |
| 81 | + |
| 82 | +### Space Complexity: O(k) |
| 83 | + |
| 84 | +as we create a counting array of size 'k'. |
| 85 | + |
| 86 | +## Code |
| 87 | + |
| 88 | +```dart |
| 89 | +class Solution { |
| 90 | + int subarraysDivByK(List<int> nums, int k) { |
| 91 | + // Use counting array to record the frequency of all the prefix sum remainders. |
| 92 | + List<int> counting = List.filled(k, 0); |
| 93 | + for (int i = 0; i < nums.length; i++) { |
| 94 | + if (i > 0) nums[i] += nums[i - 1]; |
| 95 | + // Note that the integer in 'nums' can be negative. |
| 96 | + // Thus, we need to adjust the negative remainder to positive remainder. |
| 97 | + // Below accounts for both negative and positive remainders. |
| 98 | + // We can also check if the remainder is negative, then add a 'k' to make the remainder positive. |
| 99 | + // For Example, nums = [-2,3,2], k = 5, |
| 100 | + // remainder for the prefix sum of [-2,1,3] are -2, 1 and 3 respectively. |
| 101 | + // We know that [3,2] sum to 5, which is divisible by 5. |
| 102 | + // After converting -2 to 3, by adding 5, it has the same remainder with prefix sum 3. |
| 103 | + counting[(nums[i] % k + k) % k]++; |
| 104 | + } |
| 105 | +
|
| 106 | + // The result contains all the prefix sum with remainder 0, |
| 107 | + // as all the prefix sum with remainder of 0 is itself divisible by 'k'. |
| 108 | + // However, do note that the prefix sum with remainder 0 also able to form sub-array sums that is divisible by 'k' |
| 109 | + // with one another, which will be calculated next. |
| 110 | + // For Example: nums = [5,5,5,5], k = 5, |
| 111 | + // The prefix sum of [5,10,15,20] are themselves divisible by 5, while also forming sub-array sums divisible by 5 |
| 112 | + // with 10 [5,5] - 5 [5] == 5, 15 [5,5,5] - 5 [5] == 10, etc. |
| 113 | + int result = counting[0]; |
| 114 | +
|
| 115 | + // The prefix sums with the same remainder can form sub-array sums that is divisible by 'k' with each other. |
| 116 | + // For each remainder, the number of sub-array that is divisible by 'k' is the number of combinations from the frequency. |
| 117 | + // Equation for the number of combinations of n items is n * "(n - 1) / 2". |
| 118 | + for (int frequency in counting) result += frequency * (frequency - 1) ~/ 2; |
| 119 | +
|
| 120 | + return result; |
| 121 | + } |
| 122 | +} |
| 123 | +``` |
| 124 | + |
| 125 | +## Code |
| 126 | + |
| 127 | +```dart |
| 128 | +class Solution { |
| 129 | + int subarraysDivByK(List<int> nums, int k) { |
| 130 | + int sum = 0; |
| 131 | + int cnt = 0; |
| 132 | + HashMap<int, int> hm = HashMap(); |
| 133 | + hm[0] = 1; |
| 134 | + for (int i = 0; i < nums.length; i++) { |
| 135 | + sum += nums[i]; |
| 136 | +
|
| 137 | + int diff = sum % k; |
| 138 | +
|
| 139 | + if (diff < 0) { |
| 140 | + diff += k; |
| 141 | + } |
| 142 | +
|
| 143 | + if (hm.containsKey(diff)) { |
| 144 | + cnt += hm[diff]!; |
| 145 | + } |
| 146 | + hm[diff] = (hm[diff] ?? 0) + 1; |
| 147 | + } |
| 148 | + return cnt; |
| 149 | + } |
| 150 | +} |
| 151 | +``` |
0 commit comments