Monday, February 15, 2016

Consecutive Subsequence

Difficulty: Moderate

12/15/2016: Consecutive Subsequence

Find the number of subsequences in a list whose sum is divisible by Integer K.

Input Format
The first line contains T, the number of testcases.
T testcases follow. Each testcase consists of 2 lines.
The first line contains n and k separated by a single space.
And the second line contains n space separated integers.
Output Format
For each test case, output the number of consecutive subsequences whose sum is divisible by k in a newline.
Constraints
1 ≤ T ≤ 20
1 ≤ n ≤ 106
1 ≤ k ≤ 100
1 ≤ a[i] ≤ 104 
Sample Input
2
5 3
1 2 3 4 1
6 2
1 2 1 2 1 2
Sample Output
4
9
Explanation
For
1 2 3 4 1
there exists, 4 subsequences whose sum is divisible by 3, they are
3
1 2
1 2 3
2 3 4
For
1 2 1 2 1 2
there exists, 9 subsequences whose sum is divisible by 2, they are
2
2
2
1 2 1
1 2 1
1 2 1 2
2 1 2 1
1 2 1 2
2 1 2 1 2


Runtime Analysis:
1 ≤ T ≤ 20 
1 ≤ n ≤ 106 
1 ≤ k ≤ 100 
1 ≤ a[i] ≤ 104 
Taking a look at the constraints,  we have 106 possible inputs per row with 20 possible test cases. This indicates that an O(n) solution would take 2 x 10possible operations. The average processor (usually assumed to be 2GHz) can do 2 x 109  possible operations per second. However each line of code often takes more than 1 operation to perform, so we often estimate 2 x 10operations per second (off by factor of 10), which means that, for a linear solution, we can execute our code within 1 second and is most likely a viable solution.
Notice here that a O(n2) solution would take approximately 2 x 1013 operations to complete which would likely take 105 seconds to complete, which will definitely cause a timeout.

Algorithmic Approach:
With all questions related to consecutive sums, this problem revolves around the concept of creating an accumulative sum_array. Each index i in the sum_array is the sum of all values arr[j] where 0 <= j <= i. This just basically means that each element in the sum array is equal to the sum of all values up to and inclusive of the index in the original array. The sum_array takes O(n) to compute.

Sample Array:  [1, 2, 1, 2, 1, 2]
Sum Array:       [1, 3, 4, 6, 7, 9]

Thus, when you subtract 2 entries in the sum_array where i < j:
sum_array[j] - sum_array[i] 

You have computed the sum of the subsequence from i+1 to j in O(1) time

However, just knowing about the sum_array is not enough to solve this problem. You need to find every possible subsequence from this array and that is an O(n2) runtime. However, there is a trick! Since we only care about the result of (sum % k), if the modulus of any of the values in the array are ever equal, we know that the subsequence in between must be divisible by k. Thus, we can find the total number of subsequence sums which are divisible by k, by using an array of size k to track how many values result in a remainder of (0, 1, 2 ... k-1). After doing this, we have 2 final steps.

1. Count the values in sum_array which are divisible by k
2. Sum each value in our k-sized array from 1 to arr[i]-1

Find the sum of (1) and (2) and you have your answer!

Java Code:
static long kSub(int k, int[] nums) {  
int [] sum = new int[nums.length]; long count = 0; sum[0] = nums[0]; for(int i = 1; i < nums.length; i++){ sum[i] = sum[i-1] + nums[i]; } int [] kVal = new int[k]; for(int i = 0; i < sum.length; i++){ int mod = sum[i] % k;
if(mod == 0) count++;
count += kVal[mod]; kVal[mod] += 1; } return count; }

No comments:

Post a Comment