Related Articles
Numbers that are bitwise AND of at least one non-empty sub-array
• Last Updated : 02 Aug, 2019

Given an array ‘arr’, the task is to find all possible integers each of which is the bitwise AND of at least one non-empty sub-array of ‘arr’.

Examples:

```Input: arr = {11, 15, 7, 19}
Output: [3, 19, 7, 11, 15]
3 = arr[2] AND arr[3]
19 = arr[3]
7 = arr[2]
11 = arr[0]
15 = arr[1]

Input: arr = {5, 2, 8, 4, 1}
Output: [0, 1, 2, 4, 5, 8]
0 = arr[3] AND arr[4]
1 = arr[4]
2 = arr[1]
4 = arr[3]
5 = arr[0]
8 = arr[2]
```

## Recommended: Please try your approach on {IDE} first, before moving on to the solution.

Naive Approach:

• An array of size ‘N’ contains N*(N+1)/2 sub-arrays. So, for small ‘N’, iterate over all possible sub-arrays and add each of their AND result to a set.
• Since, sets do not contain duplicates, it’ll store each value only once.
• Finally, print the contents of the set.

Below is the implementation of the above approach:

## C++

 `// C++ implementation of the approach``#include ``using` `namespace` `std;`` ` `int` `main()``{``    ``int` `A[] = {11, 15, 7, 19};``    ``int` `N = ``sizeof``(A) / ``sizeof``(A[0]);`` ` `    ``// Set to store all possible AND values.``    ``unordered_set<``int``> s;``    ``int` `i, j, res;`` ` `    ``// Starting index of the sub-array.``    ``for` `(i = 0; i < N; ++i)`` ` `        ``// Ending index of the sub-array.``        ``for` `(j = i, res = INT_MAX; j < N; ++j)``        ``{``            ``res &= A[j];`` ` `            ``// AND value is added to the set.``            ``s.insert(res);``        ``}`` ` `    ``// The set contains all possible AND values.``    ``for` `(``int` `i : s)``        ``cout << i << ``" "``;`` ` `    ``return` `0;``}`` ` `// This code is contributed by``// sanjeev2552`

## Java

 `// Java implementation of the approach``import` `java.util.HashSet;``class` `CP {``    ``public` `static` `void` `main(String[] args)``    ``{``        ``int``[] A = { ``11``, ``15``, ``7``, ``19` `};``        ``int` `N = A.length;`` ` `        ``// Set to store all possible AND values.``        ``HashSet set = ``new` `HashSet<>();``        ``int` `i, j, res;`` ` `        ``// Starting index of the sub-array.``        ``for` `(i = ``0``; i < N; ++i)`` ` `            ``// Ending index of the sub-array.``            ``for` `(j = i, res = Integer.MAX_VALUE; j < N; ++j) {``                ``res &= A[j];`` ` `                ``// AND value is added to the set.``                ``set.add(res);``            ``}`` ` `        ``// The set contains all possible AND values.``        ``System.out.println(set);``    ``}``}`

## Python3

 `# Python3 implementation of the approach `` ` `A ``=` `[``11``, ``15``, ``7``, ``19``]  ``N ``=` `len``(A) `` ` `# Set to store all possible AND values. ``Set` `=` `set``() `` ` `# Starting index of the sub-array. ``for` `i ``in` `range``(``0``, N): `` ` `    ``# Ending index of the sub-array.``    ``res ``=` `2147483647`    `# Integer.MAX_VALUE``    ``for` `j ``in` `range``(i, N):  ``        ``res &``=` `A[j] `` ` `        ``# AND value is added to the set. ``        ``Set``.add(res) ``              ` `# The set contains all possible AND values. ``print``(``Set``)`` ` `# This code is contributed by Rituraj Jain`

## C#

 `// C# implementation of the approach ``using` `System;``using` `System.Collections.Generic;`` ` `class` `CP { `` ` `    ``public` `static` `void` `Main(String[] args) ``    ``{ ``        ``int``[] A = {11, 15, 7, 19}; ``        ``int` `N = A.Length; `` ` `        ``// Set to store all possible AND values. ``        ``HashSet<``int``> set1 = ``new` `HashSet<``int``>(); ``        ``int` `i, j, res;`` ` `        ``// Starting index of the sub-array. ``        ``for` `(i = 0; i < N; ++i) ``        ``{``            ``// Ending index of the sub-array. ``            ``for` `(j = i, res = ``int``.MaxValue; j < N; ++j)``            ``{ ``                ``res &= A[j]; ``                 ` `                ``// AND value is added to the set. ``                ``set1.Add(res); ``            ``}``             ` `        ``}``         ` `        ``// displaying the values``        ``foreach``(``int` `m ``in` `set1)``        ``{``            ``Console.Write(m + ``" "``);``        ``}``         ` `    ``} ``} `
Output:

```[3, 19, 7, 11, 15]
```

Time Complexity: O(N^2)

Efficient Approach: This problem can be solved efficiently by divide-and-conquer approach.

• Consider each element of the array as a single segment. (‘Divide’ step)
• Add the AND value of all the subarrays to the set.
• Now, for the ‘conquer’ step, keep merging consecutive subarrays and keep adding the additional AND values obtained while merging.
• Continue step 4, until a single segment containing the entire array is obtained.

Below is the implementation of the above approach:

 `// Java implementation of the approach``import` `java.util.*;`` ` `public` `class` `CP {``    ``static` `int` `ar[];``    ``static` `int` `n;`` ` `    ``// Holds all possible AND results``    ``static` `HashSet allPossibleAND;`` ` `    ``// driver code``    ``public` `static` `void` `main(String[] args)``    ``{``        ``ar = ``new` `int``[] { ``11``, ``15``, ``7``, ``19` `};``        ``n = ar.length;`` ` `        ``allPossibleAND = ``new` `HashSet<>(); ``// initialization``        ``divideThenConquer(``0``, n - ``1``);`` ` `        ``System.out.println(allPossibleAND);``    ``}`` ` `    ``// recursive function which adds all``    ``// possible AND results to 'allPossibleAND'``    ``static` `Segment divideThenConquer(``int` `l, ``int` `r)``    ``{`` ` `        ``// can't divide into ``        ``//further segments``        ``if` `(l == r)``        ``{``            ``allPossibleAND.add(ar[l]);`` ` `            ``// Therefore, return a segment``            ``// containing this single element.``            ``Segment ret = ``new` `Segment();``            ``ret.leftToRight.add(ar[l]);``            ``ret.rightToLeft.add(ar[l]);``            ``return` `ret;``        ``}`` ` `        ``// can be further divided into segments``        ``else` `{``            ``Segment left ``                ``= divideThenConquer(l, (l + r) / ``2``);``            ``Segment right ``                ``= divideThenConquer((l + r) / ``2` `+ ``1``, r);`` ` `            ``// Now, add all possible AND results,``            ``// contained in these two segments`` ` `            ``/* ********************************``            ``This step may seem to be inefficient ``            ``and time consuming, but it is not.``            ``Read the 'Analysis' block below for ``            ``further clarification.``            ``*********************************** */``            ``for` `(``int` `itr1 : left.rightToLeft)``                ``for` `(``int` `itr2 : right.leftToRight)``                    ``allPossibleAND.add(itr1 & itr2);`` ` `            ``// 'conquer' step``            ``return` `mergeSegments(left, right);``        ``}``    ``}`` ` `    ``// returns the resulting segment after``    ``// merging segments 'a' and 'b'``    ``// 'conquer' step``    ``static` `Segment mergeSegments(Segment a, Segment b)``    ``{``        ``Segment res = ``new` `Segment();`` ` `        ``// The resulting segment will have``        ``// same prefix sequence as segment 'a'``        ``res.copyLR(a.leftToRight);`` ` `        ``// The resulting segment will have``        ``// same suffix sequence as segment 'b'``        ``res.copyRL(b.rightToLeft);`` ` `        ``Iterator itr;`` ` `        ``itr = b.leftToRight.iterator();``        ``while` `(itr.hasNext())``            ``res.addToLR(itr.next());`` ` `        ``itr = a.rightToLeft.iterator();``        ``while` `(itr.hasNext())``            ``res.addToRL(itr.next());`` ` `        ``return` `res;``    ``}``}`` ` `class` `Segment {`` ` `    ``// These 'vectors' will always ``    ``// contain atmost 30 values.``    ``ArrayList leftToRight ``        ``= ``new` `ArrayList<>();``    ``ArrayList rightToLeft ``        ``= ``new` `ArrayList<>();`` ` `    ``void` `addToLR(``int` `value)``    ``{``        ``int` `lastElement ``            ``= leftToRight.get(leftToRight.size() - ``1``);`` ` `        ``// value decreased after AND-ing with 'value'``        ``if` `((lastElement & value) < lastElement)``            ``leftToRight.add(lastElement & value);``    ``}`` ` `    ``void` `addToRL(``int` `value)``    ``{``        ``int` `lastElement ``            ``= rightToLeft.get(rightToLeft.size() - ``1``);`` ` `        ``// value decreased after AND-ing with 'value'``        ``if` `((lastElement & value) < lastElement)``            ``rightToLeft.add(lastElement & value);``    ``}`` ` `    ``// copies 'lr' to 'leftToRight'``    ``void` `copyLR(ArrayList lr)``    ``{``        ``Iterator itr = lr.iterator();``        ``while` `(itr.hasNext())``            ``leftToRight.add(itr.next());``    ``}`` ` `    ``// copies 'rl' to 'rightToLeft'``    ``void` `copyRL(ArrayList rl)``    ``{``        ``Iterator itr = rl.iterator();``        ``while` `(itr.hasNext())``            ``rightToLeft.add(itr.next());``    ``}``}`
Output:
```[19, 3, 7, 11, 15]
```

Analysis:

The major optimization in this algorithm is realizing that any array element can yield a maximum of 30 distinct integers (as 30 bits are needed to hold 1e9). Confused?? Let’s proceed step by step.

Let us start a sub-array from the ith element which is A[i]. As the succeeding elements are AND-ed with Ai, the result can either decrease or remain same (because a bit will never get changed from ‘0’ to ‘1’ after an AND operation).
In the worst case, A[i] can be 2^31 – 1 (all 30 bits will be ‘1’). As the elements are AND-ed, atmost 30 distinct values can be obtained because only a single bit might get changed from ‘1’ to ‘0’ in the worst case,
i.e. 111111111111111111111111111111 => 111111111111111111111111101111

So, for each ‘merge’ operation, these distinct values merge to form another set having atmost 30 integers.
Therefore, Worst Case Time Complexity for each merge can be O(30 * 30) = O(900).

Time Complexity: O(900*N*logN).

PS: The time complexity can seem too high, but in practice, the actual complexity lies around O(K*N*logN), where, K is much less than 900. This is because, the lengths of the ‘prefix’ and ‘suffix’ arrays are much less when ‘l’ and ‘r’ are quite close.

Attention reader! Don’t stop learning now. Get hold of all the important DSA concepts with the DSA Self Paced Course at a student-friendly price and become industry ready.  To complete your preparation from learning a language to DS Algo and many more,  please refer Complete Interview Preparation Course.

In case you wish to attend live classes with industry experts, please refer DSA Live Classes

My Personal Notes arrow_drop_up