Find a non empty subset in an array of N integers such that sum of elements of subset is divisible by N
Last Updated :
06 Mar, 2023
Given an array of N integers, the task is to find a non-empty subset such that the sum of elements of the subset is divisible by N. Output any such subset with its size and the indices(1-based indexing) of elements in the original array if it exists.
Prerequisites: Pigeonhole Principle
Examples:
Input: arr[] = { 2, 3, 7, 1, 9 }
Output: 2
1 2
The required subset is { 2, 3 } whose indices are 1 and 2.
Input: arr[] = {2, 11, 4}
Output: 2
2 3
A naive approach will be to generate all possible subsets by using the Power Set of the given array, calculate their respective sums and check if the sum is divisible by N.
Time Complexity: O(2N * N), O(2N) for generating all subsets, and O(N) for calculating the sum of every subset.
Efficient Approach: On considering Prefix Sums, we obtain:
prefixSum0 = arr0
prefixSum1 = arr0 + arr1
prefixSum2 = arr0 + arr1 + arr2
…
prefixSumN = arr0 + arr1 + arr2 + … + arrN
It can be seen easily that arrL + arrL+1 + … + arrR (L ? R) equals to prefixSumR –
prefixSumL-1. If the sum of any contiguous subsegment is divisible by N, then it
means the residue upon taking modulo N of prefixSumR – prefixSumL-1
is zero, i.e.
(prefixSumR – prefixSumL-1) % N = 0;
Splitting the modulo,
prefixSumR % N – prefixSumL-1 % N = 0
prefixSumR % N = prefixSumL-1 % N.
Since there are (N) values of prefixSums and N possible residues for N (0, 1, 2 … N-2, N-1). Hence, according to the pigeonhole principle there always exists a contiguous subsegment whose prefixSum extremities are equal. If at any instance, prefixL, then the first L indexes will give the subset.
Steps were to solve the above approach:
- Initialize an empty unordered_map mp that will store the residue of the prefix sum and its index.
- Initialize a variable sum to 0.
- Iterate over the array arr with index i from 0 to N-1:
- Add the value of arr[i] to sum.
- Take the residue of sum with N, i.e., sum = sum % N.
- If sum is equal to 0:
- Print the size of the subsegment which is (i+1).
- Print the indices of the subsegment which are from 0 to i.
- Return from the function.
- If sum is already in the map:
- Print the size of the subsegment which is (i – mp[sum]).
- Print the indices of the subsegment which are from (mp[sum]+1) to i.
- Return from the function.
- Else mp[sum]=i.
Below is the code to implement the above approach:
C++
#include <bits/stdc++.h>
using namespace std;
void findNonEmptySubset( int arr[], int N)
{
unordered_map< int , int > mp;
int sum = 0;
for ( int i = 0; i < N; i++) {
sum = (sum + arr[i]) % N;
if (sum == 0) {
cout << i + 1 << endl;
for ( int j = 0; j <= i; j++)
cout << j + 1 << " " ;
return ;
}
if (mp.find(sum) != mp.end()) {
cout << (i - mp[sum]) << endl;
for ( int j = mp[sum] + 1; j <= i; j++)
cout << j + 1 << " " ;
return ;
}
else
mp[sum] = i;
}
}
int main()
{
int arr[] = { 2, 3, 7, 1, 9 };
int N = sizeof (arr) / sizeof (arr[0]);
findNonEmptySubset(arr, N);
return 0;
}
|
Java
import java.io.*;
import java.util.HashMap;
import java.util.Map.Entry;
import java.util.Map;
import java.lang.*;
class GFG
{
static void findNonEmptySubset( int arr[],
int N)
{
HashMap<Integer, Integer> mp =
new HashMap<Integer, Integer>();
int sum = 0 ;
for ( int i = 0 ; i < N; i++)
{
sum = (sum + arr[i]) % N;
if (sum == 0 )
{
System.out.print(i + 1 + "\n" );
for ( int j = 0 ; j <= i; j++)
System.out.print(j + 1 + " " );
return ;
}
if (mp.containsKey(sum) == true )
{
System.out.println((i -
mp.get(sum)));
for ( int j = mp.get(sum) + 1 ;
j <= i; j++)
System.out.print(j + 1 + " " );
return ;
}
else
mp.put(sum,i);
}
}
public static void main(String[] args)
{
int arr[] = { 2 , 3 , 7 , 1 , 9 };
int N = arr.length;
findNonEmptySubset(arr, N);
}
}
|
Python3
def findNonEmptySubset(arr, N):
mp = {}
Sum = 0
for i in range (N):
Sum = ( Sum + arr[i]) % N
if ( Sum = = 0 ) :
print (i + 1 )
for j in range (i + 1 ):
print (j + 1 , end = " " )
return
if Sum in mp :
print ((i - mp[ Sum ]))
for j in range (mp[ Sum ] + 1 ,
i + 1 ):
print (j + 1 , end = " " )
return
else :
mp[ Sum ] = i
arr = [ 2 , 3 , 7 , 1 , 9 ]
N = len (arr)
findNonEmptySubset(arr, N)
|
C#
using System;
using System.Collections ;
class GFG
{
static void findNonEmptySubset( int []arr, int N)
{
Hashtable mp = new Hashtable();
int sum = 0;
for ( int i = 0; i < N; i++)
{
sum = (sum + arr[i]) % N;
if (sum == 0)
{
Console.Write(i + 1 + "\n" );
for ( int j = 0; j <= i; j++)
Console.Write(j + 1 + " " );
return ;
}
if (mp.ContainsKey(sum) == true )
{
Console.WriteLine(i - Convert.ToInt32(mp[sum]));
for ( int j = Convert.ToInt32(mp[sum]) + 1;
j <= i; j++)
Console.Write(j + 1 + " " );
return ;
}
else
mp.Add(sum,i);
}
}
public static void Main()
{
int []arr = { 2, 3, 7, 1, 9 };
int N = arr.Length;
findNonEmptySubset(arr, N);
}
}
|
Javascript
<script>
function findNonEmptySubset( arr , N)
{
var mp = new Map();
var sum = 0;
for (let i = 0; i < N; i++)
{
sum = (sum + arr[i]) % N;
var str= "" ;
if (sum == 0)
{
console.log(i + 1 );
for (let j = 0; j <= i; j++)
str+=j + 1 + " " ;
console.log(str);
return ;
}
if (mp.has(sum))
{
console.log(i - mp[sum]);
for (let j = mp[sum] + 1; j <= i; j++)
str+=j + 1 + " " ;
console.log(str);
return ;
}
else
mp[sum] = i;
}
}
var arr = new Array( 2, 3, 7, 1, 9 );
var N = arr.length;
findNonEmptySubset(arr, N);
</script>
|
Time Complexity: O(N), where N is the size of the array.
Auxiliary Space: O(N)
Like Article
Suggest improvement
Share your thoughts in the comments
Please Login to comment...