# 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.

My Personal Notes arrow_drop_up