Size of the smallest subset with maximum Bitwise OR
Given an array of positive integers. The task is to find the size of the smallest subset such that the Bitwise OR of that set is Maximum possible.
Examples:
Input : arr[] = {5, 1, 3, 4, 2}
Output : 2
Explanation: 7 is the maximum value possible of OR, 5|2 = 7 and 5|3 = 7
Input : arr[] = {2, 6, 2, 8, 4, 5}
Output : 3
Explanation: 15 is the maximum value of OR and set elements are 8, 6, 5
Source: Sprinklr on Campus Internship
Doing bitwise OR of a number with some value does not decrease its value. It either keeps the value the same or increases. If we take a closer look at the problem we can notice that the maximum OR value that we can get is by doing bitwise OR of all array elements. But this includes all elements and here want to know the smallest subset. So we do the following.
- Find bitwise OR of all array elements. This is the OR we are looking for.
- Now we need to find the smallest subset with this bitwise OR. This problem is similar to the subset-sum problem, We can solve it in two ways :
- We generate all subsets and return the smallest size with the given OR
- We use Dynamic Programming to solve the problem. This solution is going to be very similar to Maximum size subset with given sum
The time complexity of the 1st solution is O(2n) and the time complexity of the Dynamic Programming solution is O(OR * n) where OR is OR of all array elements and n is the size of the input array.
Using Method 1 : (generating all subsets and returning the smallest size with the given OR)
Implementation:
C++
#include <bits/stdc++.h>
using namespace std;
int OR( int data[], int sz)
{
int mOR = 0;
for ( int i = 0; i < sz; ++i) {
mOR |= data[i];
}
return mOR;
}
int minSubset( int data[], int sz, int maxOR)
{
int minSZ=sz;
for ( int mask=0;mask<(1<<sz);mask++)
{
int curSZ=0;
int curOR=0;
for ( int i=0;i<sz;i++)
{
if (mask&(1<<i))
{
curSZ++;
curOR|=data[i];
}
}
if (curOR==maxOR)
minSZ=min(minSZ,curSZ);
}
return minSZ;
}
int main()
{
int data[] = { 5, 1, 3, 4, 2 };
int sz = sizeof (data) / sizeof (0);
int maxOR = OR(data, sz);
cout << minSubset(data, sz,maxOR) << '\n' ;
}
|
Java
import java.io.*;
import java.util.*;
class Solution
{
private static int OR( int [] arr)
{
int mOR = 0 ;
for ( int i = 0 ; i < arr.length; ++i)
{
mOR |= arr[i];
}
return mOR;
}
private static int maxSubset( int [] arr, int i,
int curOr, int curSize, int maxOr)
{
if (i == arr.length)
{
if (curOr == maxOr)
{
return curSize;
}
else
{
return arr.length;
}
}
int take = maxSubset(arr, i + 1 , curOr |
arr[i], curSize + 1 , maxOr);
int notTake = maxSubset(arr, i + 1 , curOr,
curSize, maxOr);
return Math.min(take, notTake);
}
public static void main(String[] args)
{
int [] data = { 5 , 1 , 3 , 4 , 2 };
int maxOr = OR(data);
int maxSubsetSize = maxSubset(data, 0 , 0 , 0 , maxOr);
System.out.println(maxSubsetSize);
}
}
|
Python3
def OR(data, sz):
mOR = 0
for i in range (sz) :
mOR | = data[i]
return mOR
def minSubset(data, sz,maxOR):
minSZ = sz
for mask in range ( 1 <<sz):
curSZ = 0
curOR = 0
for i in range (sz):
if (mask&( 1 <<i)):
curSZ + = 1
curOR| = data[i]
if (curOR = = maxOR):
minSZ = min (minSZ,curSZ)
return minSZ
if __name__ = = '__main__' :
data = [ 5 , 1 , 3 , 4 , 2 ]
sz = len (data)
maxOR = OR(data, sz)
print (minSubset(data, sz,maxOR))
|
C#
using System;
class Solution
{
private static int OR( int [] arr)
{
int mOR = 0;
for ( int i = 0; i < arr.Length; ++i)
{
mOR |= arr[i];
}
return mOR;
}
private static int maxSubset( int [] arr, int i,
int curOr, int curSize, int maxOr)
{
if (i == arr.Length)
{
if (curOr == maxOr)
{
return curSize;
}
else
{
return arr.Length;
}
}
int take = maxSubset(arr, i + 1, curOr |
arr[i], curSize + 1, maxOr);
int notTake = maxSubset(arr, i + 1, curOr,
curSize, maxOr);
return Math.Min(take, notTake);
}
static void Main()
{
int [] data = {5, 1, 3, 4, 2};
int maxOr = OR(data);
int maxSubsetSize = maxSubset(data, 0, 0, 0, maxOr);
Console.WriteLine(maxSubsetSize);
}
}
|
Javascript
<script>
function OR(arr)
{
let mOR = 0;
for (let i = 0; i < arr.length; ++i)
{
mOR |= arr[i];
}
return mOR;
}
function maxSubset(arr,i,curOr,curSize,maxOr)
{
if (i == arr.length)
{
if (curOr == maxOr)
{
return curSize;
}
else
{
return arr.length;
}
}
let take = maxSubset(arr, i + 1, curOr |
arr[i], curSize + 1, maxOr);
let notTake = maxSubset(arr, i + 1, curOr,
curSize, maxOr);
return Math.min(take, notTake);
}
let data=[5, 1, 3, 4, 2];
let maxOr = OR(data);
let maxSubsetSize = maxSubset(data, 0, 0, 0, maxOr);
document.write(maxSubsetSize);
</script>
|
Complexity Analysis:
- Time complexity: O(2n)
- Auxiliary Space: O(n)
Using Method 2:
We first find the OR of all elements of given array.Now we need to find the smallest subset with this bitwise OR.
To do so, use the similar DP approach as given in the subset sum problem. count[i][j] denotes the minimum size subset till ith element whose OR is j.
Implementation:
C++
#include <bits/stdc++.h>
using namespace std;
int OR( int data[], int sz)
{
int mOR = 0;
for ( int i = 0; i < sz; ++i) {
mOR |= data[i];
}
return mOR;
}
int minSubset( int data[], int sz, int maxOR)
{
vector<vector< int > > count(sz + 1, vector< int >(maxOR + 1, 1e9));
count[0][0] = 0;
for ( int i = 0; i < sz; i++) {
for ( int j = 0; j <= maxOR; j++) {
count[i + 1][j] = min(count[i + 1][j], count[i][j]);
if (count[i][j] != 1e9) {
count[i + 1][j | data[i]] = min(
count[i + 1][j | data[i]], count[i][j] + 1);
}
}
}
return count[sz][maxOR];
}
int main()
{
int data[] = { 5, 1, 3, 4, 2 };
int sz = sizeof (data) / sizeof (0);
int maxOR = OR(data, sz);
cout << minSubset(data, sz, maxOR) << '\n' ;
}
|
Java
import java.io.*;
import java.util.*;
class GFG {
static int OR( int data[], int sz)
{
int mOR = 0 ;
for ( int i = 0 ; i < sz; ++i) {
mOR |= data[i];
}
return mOR;
}
static int minSubset( int data[], int sz, int maxOR)
{
int count[][] = new int [sz + 1 ][maxOR + 1 ];
for ( int i= 0 ;i<sz+ 1 ;i++){
Arrays.fill(count[i], 1000000000 );
}
count[ 0 ][ 0 ] = 0 ;
for ( int i = 0 ; i < sz; i++) {
for ( int j = 0 ; j <= maxOR; j++) {
count[i + 1 ][j] = Math.min(count[i + 1 ][j], count[i][j]);
if (count[i][j] != 1000000000 ) {
count[i + 1 ][j | data[i]] = Math.min(
count[i + 1 ][j | data[i]], count[i][j] + 1 );
}
}
}
return count[sz][maxOR];
}
public static void main(String args[])
{
int data[] = { 5 , 1 , 3 , 4 , 2 };
int sz = data.length;
int maxOR = OR(data, sz);
System.out.println(minSubset(data, sz, maxOR));
}
}
|
Python3
def OR(data, sz):
mOR = 0
for i in range (sz):
mOR | = data[i]
return mOR
def minSubset(data, sz, maxOR):
count = [[ 1e9 for _ in range (maxOR + 1 )] for _ in range (sz + 1 )]
count[ 0 ][ 0 ] = 0
for i in range (sz) :
for j in range (maxOR) :
count[i + 1 ][j] = min (count[i + 1 ][j], count[i][j])
if (count[i][j] ! = 1e9 ) :
count[i + 1 ][j | data[i]] = min (
count[i + 1 ][j | data[i]], count[i][j] + 1 )
return count[sz][maxOR]
if __name__ = = '__main__' :
data = [ 5 , 1 , 3 , 4 , 2 ]
sz = len (data)
maxOR = OR(data, sz)
print (minSubset(data, sz, maxOR))
|
C#
using System;
class GFG {
static int OR( int [] data, int sz)
{
int mOR = 0;
for ( int i = 0; i < sz; ++i) {
mOR |= data[i];
}
return mOR;
}
static int minSubset( int [] data, int sz, int maxOR)
{
int [, ] count = new int [sz + 1, maxOR + 1];
for ( int i = 0; i <= sz; i++) {
for ( int j = 0; j <= maxOR; j++) {
count[i, j] = ( int )1e9;
}
}
count[0, 0] = 0;
for ( int i = 0; i < sz; i++) {
for ( int j = 0; j <= maxOR; j++) {
count[i + 1, j] = Math.Min(count[i + 1, j],
count[i, j]);
if (count[i, j] != 1e9) {
count[i + 1, j | data[i]] = Math.Min(
count[i + 1, j | data[i]],
count[i, j] + 1);
}
}
}
return count[sz, maxOR];
}
public static void Main()
{
int [] data = { 5, 1, 3, 4, 2 };
int sz = 5;
int maxOR = OR(data, sz);
Console.WriteLine(minSubset(data, sz, maxOR));
}
}
|
Javascript
<script>
function OR(data, sz){
let mOR = 0
for (let i=0;i<sz;i++)
mOR |= data[i]
return mOR
}
function minSubset(data, sz, maxOR){
let count = new Array(sz+1).fill(0).map(()=> new Array(maxOR+1).fill(1e9));
count[0][0] = 0
for (let i=0;i<sz;i++){
for (let j=0;j<maxOR;j++){
count[i + 1][j] = Math.min(count[i + 1][j], count[i][j])
if (count[i][j] != 1e9)
count[i + 1][j | data[i]] = Math.min(
count[i + 1][j | data[i]], count[i][j] + 1)
}
}
return count[sz][maxOR]
}
let data = [5, 1, 3, 4, 2]
let sz = data.length
let maxOR = OR(data, sz)
document.write(minSubset(data, sz, maxOR), "</br>" )
</script>
|
Complexity Analysis:
- Time complexity: O(n*maxOR) where n is the size of the array and maxOR is the maximum or that can be obtained.
- Auxiliary Space: O(n*maxOR)
Efficient approach : Space optimization
In previous approach the current value count[i][j] is only depend upon the current and previous row values of DP. So to optimize the space complexity we use a single 1D array to store the computations.
Implementation steps:
- Create a 1D vector count of size maxOR+1 and initialize it with 0.
- Set a base case by initializing the values of count.
- Now iterate over subproblems by the help of nested loop and get the current value from previous computations.
- Now Create a temporary 1d vector temp used to store the current values from previous computations.
- After every iteration assign the value of temp to count for further iteration.
- At last return and print the final answer stored in count[maxOR].
Implementation:
C++
#include <bits/stdc++.h>
using namespace std;
int OR( int data[], int sz)
{
int mOR = 0;
for ( int i = 0; i < sz; ++i) {
mOR |= data[i];
}
return mOR;
}
int minSubset( int data[], int sz, int maxOR)
{
vector< int > count(maxOR + 1, 1e9);
count[0] = 0;
for ( int i = 0; i < sz; i++) {
vector< int > temp(maxOR + 1, 1e9);
for ( int j = 0; j <= maxOR; j++) {
temp[j] = min(temp[j], count[j]);
if (count[j] != 1e9) {
temp[j | data[i]] = min(
temp[j | data[i]], count[j] + 1);
}
}
count = temp;
}
return count[maxOR];
}
int main()
{
int data[] = { 5, 1, 3, 4, 2 };
int sz = sizeof (data) / sizeof (0);
int maxOR = OR(data, sz);
cout << minSubset(data, sz, maxOR) << '\n' ;
}
|
Java
import java.util.Arrays;
public class MinimumSubsetMaxOR {
static int OR( int [] data) {
int mOR = 0 ;
for ( int i : data) {
mOR |= i;
}
return mOR;
}
static int minSubset( int [] data, int maxOR) {
int sz = data.length;
int [][] count = new int [sz + 1 ][maxOR + 1 ];
for ( int i = 0 ; i <= sz; i++) {
Arrays.fill(count[i], Integer.MAX_VALUE);
}
count[ 0 ][ 0 ] = 0 ;
for ( int i = 1 ; i <= sz; i++) {
for ( int j = 0 ; j <= maxOR; j++) {
count[i][j] = Math.min(count[i][j], count[i - 1 ][j]);
if (count[i - 1 ][j] != Integer.MAX_VALUE) {
count[i][j | data[i - 1 ]] = Math.min(count[i][j | data[i - 1 ]], count[i - 1 ][j] + 1 );
}
}
}
return count[sz][maxOR];
}
public static void main(String[] args) {
int [] data = { 5 , 1 , 3 , 4 , 2 };
int maxOR = OR(data);
System.out.println(minSubset(data, maxOR));
}
}
|
Python
def OR(data, sz):
mOR = 0
for i in range (sz):
mOR | = data[i]
return mOR
def minSubset(data, sz, maxOR):
count = [ float ( 'inf' )] * (maxOR + 1 )
count[ 0 ] = 0
for i in range (sz):
temp = [ float ( 'inf' )] * (maxOR + 1 )
for j in range (maxOR + 1 ):
temp[j] = min (temp[j], count[j])
if count[j] ! = float ( 'inf' ):
temp[j | data[i]] = min (temp[j | data[i]], count[j] + 1 )
count = temp
return count[maxOR]
if __name__ = = "__main__" :
data = [ 5 , 1 , 3 , 4 , 2 ]
sz = len (data)
maxOR = OR(data, sz)
print (minSubset(data, sz, maxOR))
|
C#
using System;
class MinimumSubsetMaxOR
{
static int OR( int [] data)
{
int mOR = 0;
foreach ( int i in data)
{
mOR |= i;
}
return mOR;
}
static int MinSubset( int [] data, int maxOR)
{
int sz = data.Length;
int [,] count = new int [sz + 1, maxOR + 1];
for ( int i = 0; i <= sz; i++)
{
for ( int j = 0; j <= maxOR; j++)
{
count[i, j] = int .MaxValue;
}
}
count[0, 0] = 0;
for ( int i = 1; i <= sz; i++)
{
for ( int j = 0; j <= maxOR; j++)
{
count[i, j] = Math.Min(count[i, j], count[i - 1, j]);
if (count[i - 1, j] != int .MaxValue)
{
count[i, j | data[i - 1]] = Math.Min(count[i, j | data[i - 1]],
count[i - 1, j] + 1);
}
}
}
return count[sz, maxOR];
}
static void Main( string [] args)
{
int [] data = { 5, 1, 3, 4, 2 };
int maxOR = OR(data);
Console.WriteLine(MinSubset(data, maxOR));
}
}
|
Javascript
function OR(data) {
let mOR = 0;
for (let i = 0; i < data.length; ++i) {
mOR |= data[i];
}
return mOR;
}
function minSubset(data, maxOR) {
let count = new Array(maxOR + 1).fill(Infinity);
count[0] = 0;
for (let i = 0; i < data.length; i++) {
let temp = new Array(maxOR + 1).fill(Infinity);
for (let j = 0; j <= maxOR; j++) {
temp[j] = Math.min(temp[j], count[j]);
if (count[j] !== Infinity) {
temp[j | data[i]] = Math.min(temp[j | data[i]], count[j] + 1);
}
}
count = temp;
}
return count[maxOR];
}
const data = [5, 1, 3, 4, 2];
const maxOR = OR(data);
console.log(minSubset(data, maxOR));
|
Time complexity: O(n*maxOR) where n is the size of the array and maxOR is the maximum or that can be obtained.
Auxiliary Space: O(maxOR)
Using method 3: Backtracking Approach
Implementation steps:
- Compute the bitwise or of all elements in array of size.
- Write the recursive function to find the size of the smallest element
- such that bitwise OR of that set is maximum possible.
- If the current OR value is already equal to the maximum OR value, update the minimum subset size and return.
- If we have already considered all the elements in the array, return without updating the minimum subset size.
- Write the Backtracking step.
- remove the current element from the subset and recurse.
- include the current element in the subset and recurse.
- Calculate the size of minimum subset with maximum or.
- Recursive function to find the size of the smallest subset such that the Bitwise OR of that set is Maximum possible.
- Last return and print.
Code implementation for above approach:
C++
#include <bits/stdc++.h>
using namespace std;
int OR( int data[], int sz)
{
int mOR = 0;
for ( int i = 0; i < sz; ++i) {
mOR |= data[i];
}
return mOR;
}
void minSubsetUtil( int data[], int sz, int ORval,
int currOR, int subsetSize, int & minSize)
{
if (currOR == ORval) {
minSize = min(minSize, subsetSize);
return ;
}
if (sz == 0) {
return ;
}
minSubsetUtil(data + 1, sz - 1, ORval, currOR,
subsetSize, minSize);
minSubsetUtil(data + 1, sz - 1, ORval, currOR | data[0],
subsetSize + 1, minSize);
}
int minSubset( int data[], int sz, int maxOR)
{
int minSize = INT_MAX;
int currOR = 0;
int subsetSize = 0;
minSubsetUtil(data, sz, maxOR, currOR, subsetSize,
minSize);
return minSize;
}
int main()
{
int data[] = { 5, 1, 3, 4, 2 };
int sz = sizeof (data) / sizeof (0);
int maxOR = OR(data, sz);
cout << minSubset(data, sz, maxOR) << '\n' ;
}
|
Java
public class MinSubsetMaxOr {
static int OR( int data[], int sz) {
int mOR = 0 ;
for ( int i = 0 ; i < sz; ++i) {
mOR |= data[i];
}
return mOR;
}
static void minSubsetUtil( int data[], int sz, int ORval,
int currOR, int subsetSize, int [] minSize) {
if (currOR == ORval) {
minSize[ 0 ] = Math.min(minSize[ 0 ], subsetSize);
return ;
}
if (sz == 0 ) {
return ;
}
minSubsetUtil(data, sz - 1 , ORval, currOR, subsetSize, minSize);
minSubsetUtil(data, sz - 1 , ORval, currOR | data[sz - 1 ], subsetSize + 1 , minSize);
}
static int minSubset( int data[], int sz, int maxOR) {
int [] minSize = { Integer.MAX_VALUE };
int currOR = 0 ;
int subsetSize = 0 ;
minSubsetUtil(data, sz, maxOR, currOR, subsetSize, minSize);
return minSize[ 0 ];
}
public static void main(String[] args) {
int data[] = { 5 , 1 , 3 , 4 , 2 };
int sz = data.length;
int maxOR = OR(data, sz);
System.out.println(minSubset(data, sz, maxOR));
}
}
|
Python
def bitwise_or(data):
result = 0
for elem in data:
result | = elem
return result
def min_subset_util(data, sz, OR_val, curr_OR, subset_size, min_size):
if curr_OR = = OR_val:
min_size[ 0 ] = min (min_size[ 0 ], subset_size)
return
if sz = = 0 :
return
min_subset_util(data[ 1 :], sz - 1 , OR_val, curr_OR, subset_size, min_size)
min_subset_util(data[ 1 :], sz - 1 , OR_val, curr_OR | data[ 0 ], subset_size + 1 , min_size)
def min_subset(data):
sz = len (data)
max_OR = bitwise_or(data)
min_size = [ float ( 'inf' )]
curr_OR = 0
subset_size = 0
min_subset_util(data, sz, max_OR, curr_OR, subset_size, min_size)
return min_size[ 0 ]
if __name__ = = "__main__" :
data = [ 5 , 1 , 3 , 4 , 2 ]
max_OR = bitwise_or(data)
print (min_subset(data))
|
C#
using System;
class Program
{
static int OR( int [] data)
{
int mOR = 0;
foreach ( int element in data)
{
mOR |= element;
}
return mOR;
}
static void MinSubsetUtil( int [] data, int sz, int ORval,
int currOR, int subsetSize, ref int minSize)
{
if (currOR == ORval)
{
minSize = Math.Min(minSize, subsetSize);
return ;
}
if (sz == 0)
{
return ;
}
int [] subArray = new int [sz - 1];
Array.Copy(data, 1, subArray, 0, sz - 1);
MinSubsetUtil(subArray, sz - 1, ORval, currOR, subsetSize, ref minSize);
MinSubsetUtil(subArray, sz - 1, ORval, currOR | data[0], subsetSize + 1, ref minSize);
}
static int MinSubset( int [] data, int maxOR)
{
int minSize = int .MaxValue;
int currOR = 0;
int subsetSize = 0;
MinSubsetUtil(data, data.Length, maxOR, currOR, subsetSize, ref minSize);
return minSize;
}
static void Main()
{
int [] data = { 5, 1, 3, 4, 2 };
int maxOR = OR(data);
Console.WriteLine(MinSubset(data, maxOR));
}
}
|
Javascript
function OR(data) {
let mOR = 0;
for (let element of data) {
mOR |= element;
}
return mOR;
}
function minSubsetUtil(data, sz, ORval, currOR, subsetSize, minSize) {
if (currOR === ORval) {
minSize[0] = Math.min(minSize[0], subsetSize);
return ;
}
if (sz === 0) {
return ;
}
let subArray = data.slice(1);
minSubsetUtil(subArray, sz - 1, ORval, currOR, subsetSize, minSize);
minSubsetUtil(subArray, sz - 1, ORval, currOR | data[0], subsetSize + 1, minSize);
}
function minSubset(data, maxOR) {
let minSize = [Infinity];
let currOR = 0;
let subsetSize = 0;
minSubsetUtil(data, data.length, maxOR, currOR, subsetSize, minSize);
return minSize[0];
}
const data = [5, 1, 3, 4, 2];
const maxOR = OR(data);
console.log(minSubset(data, maxOR));
|
Time Complexity: O(2^N), where N is the size of the input array.
Auxiliary Space: O(N), where N is the size of the input array.
Last Updated :
30 Nov, 2023
Like Article
Save Article
Share your thoughts in the comments
Please Login to comment...