Open In App

Maximum bitwise OR value of subsequence of length K

Last Updated : 07 Dec, 2024
Comments
Improve
Suggest changes
Like Article
Like
Report

Given an array arr[] of n positive integers and an integer k, the task is to find the maximum value of the bitwise OR of any subsequence of size k.

Examples: 

Input: arr[] = [2, 5, 3, 6, 11, 13], k = 3 
Output: 15 
Explanation: The sub-sequence with maximum OR value is [2, 11, 13].

Input: arr[] = [5, 9, 7, 19], k = 3 
Output: 31 
Explanation: The sub-sequence with maximum OR value is [5, 9, 19].

Using Recursion - O(2^n) Time and O(n) Space

The idea is to use recursion to explore all possible subsequences of size k. By either including or excluding each element at a given index, we can generate all combinations. The key is to calculate the bitwise OR for each valid subsequence and return the maximum OR value among them.

The recursive relation will be -

  • include = maxOrHelper(arr, n, k, index + 1, currOR | arr[index], currSize + 1)
  • exclude = maxOrHelper(arr, n, k, index + 1, currOR, currSize);

The final result will me the max(include, exclude).

C++
// C++ implementation to find Max OR of
// subsequence of size k using Recursion
#include <bits/stdc++.h>
using namespace std;

// Helper function to calculate the maximum OR 
// of subsequences of size k
int maxOrHelper(vector<int>&arr, int n, 
               int k, int index, int currOR, 
                                  int currSize) {
  
    // If we have selected k elements, return
    // the current OR value
    if (currSize == k) {
        return currOR;
    }
    
    // If we have exhausted all elements
    if (index == n) {
        return 0;
    }
    
    // Include the current element and recurse
    int include = maxOrHelper(arr, n, k, index + 1, 
                      currOR | arr[index], currSize + 1);
    
    // Skip the current element and recurse
    int exclude = maxOrHelper(arr, n, k, index + 1,
                                      currOR, currSize);
    
    // Return the maximum of including or 
    // excluding the current element
    return max(include, exclude);
}

int maxOrK(vector<int>& arr, int k) {
    int n = arr.size();
    return maxOrHelper(arr, n, k, 0, 0, 0);
}

int main() {
  
    vector<int> arr = {2, 5, 3, 6, 11, 13};
    int k = 3;
    cout << maxOrK(arr, k); 
    return 0;
}
Java
// Java implementation to find Max OR of
// subsequence of size k using Recursion
import java.util.*;

class GfG {

    // Helper function to calculate the maximum OR 
    // of subsequences of size k
    static int maxOrHelper(List<Integer> arr, int n, 
                           int k, int index, int currOR, 
                           int currSize) {
  
        // If we have selected k elements, return
        // the current OR value
        if (currSize == k) {
            return currOR;
        }
    
        // If we have exhausted all elements
        if (index == n) {
            return 0;
        }
    
        // Include the current element and recurse
        int include = maxOrHelper(arr, n, k, index + 1, 
                        currOR | arr.get(index), currSize + 1);
    
        // Skip the current element and recurse
        int exclude = maxOrHelper(arr, n, k, index + 1, 
                                  currOR, currSize);
    
        // Return the maximum of including or 
        // excluding the current element
        return Math.max(include, exclude);
    }

    static int maxOrK(List<Integer> arr, int k) {
        int n = arr.size();
        return maxOrHelper(arr, n, k, 0, 0, 0);
    }

    public static void main(String[] args) {
  
        List<Integer> arr
            = Arrays.asList(2, 5, 3, 6, 11, 13);
      
        int k = 3;
        System.out.println(maxOrK(arr, k)); 
    }
}
Python
# Python implementation to find Max OR of
# subsequence of size k using Recursion

# Helper function to calculate the maximum OR 
# of subsequences of size k
def maxOrHelper(arr, n, k, index, currOR, currSize):

    # If we have selected k elements, return
    # the current OR value
    if currSize == k:
        return currOR
    
    # If we have exhausted all elements
    if index == n:
        return 0
    
    # Include the current element and recurse
    include = maxOrHelper(arr, n, k, index + 1,\
                   currOR | arr[index], currSize + 1)
    
    # Skip the current element and recurse
    exclude = maxOrHelper(arr, n, k,\
                         index + 1, currOR, currSize)
    
    # Return the maximum of including or 
    # excluding the current element
    return max(include, exclude)

def maxOrK(arr, k):
    n = len(arr)
    return maxOrHelper(arr, n, k, 0, 0, 0)

if __name__ == "__main__":

    arr = [2, 5, 3, 6, 11, 13]
    k = 3
    print(maxOrK(arr, k))
C#
// C# implementation to find Max OR of
// subsequence of size k using Recursion
using System;
using System.Collections.Generic;

class GfG {

    // Helper function to calculate the maximum OR 
    // of subsequences of size k
    static int maxOrHelper(List<int> arr, int n, 
                           int k, int index, int currOR, 
                           int currSize) {
  
        // If we have selected k elements, return
        // the current OR value
        if (currSize == k) {
            return currOR;
        }
    
        // If we have exhausted all elements
        if (index == n) {
            return 0;
        }
    
        // Include the current element and recurse
        int include = maxOrHelper(arr, n, k, index + 1, 
                         currOR | arr[index], currSize + 1);
    
        // Skip the current element and recurse
        int exclude = maxOrHelper(arr, n, k, index + 1, 
                                  currOR, currSize);
    
        // Return the maximum of including or 
        // excluding the current element
        return Math.Max(include, exclude);
    }

    static int maxOrK(List<int> arr, int k) {
        int n = arr.Count;
        return maxOrHelper(arr, n, k, 0, 0, 0);
    }

    static void Main(string[] args) {
  
        List<int> arr 
             = new List<int> { 2, 5, 3, 6, 11, 13 };

        int k = 3;  
        Console.WriteLine(maxOrK(arr, k)); 
    }
}
JavaScript
// JavaScript implementation to find Max OR of
// subsequence of size k using Recursion

// Helper function to calculate the maximum OR 
// of subsequences of size k
function maxOrHelper(arr, n, k, index, 
                           currOR, currSize) {

    // If we have selected k elements, return
    // the current OR value
    if (currSize === k) {
        return currOR;
    }

    // If we have exhausted all elements
    if (index === n) {
        return 0;
    }

    // Include the current element and recurse
    let include = maxOrHelper(arr, n, k, index + 1,
                   currOR | arr[index], currSize + 1);

    // Skip the current element and recurse
    let exclude = maxOrHelper(arr, n, k, index + 1,
                                  currOR, currSize);

    // Return the maximum of including or 
    // excluding the current element
    return Math.max(include, exclude);
}

function maxOrK(arr, k) {
    let n = arr.length;
    return maxOrHelper(arr, n, k, 0, 0, 0);
}

let arr = [2, 5, 3, 6, 11, 13];
let k = 3;
console.log(maxOrK(arr, k));

Output
15

Using Dynamic Programming - O(n*k*maxOR) Time and O(n*k*maxOR) Space

The idea is to optimize the recursive solution by using memoization to avoid redundant computations. Instead of recalculating the maximum OR value for the same state (defined by the index, current OR value, and size of the subsequence), we store the results in a 3D memoization table with dimensions [n][k+1][maxPossibleOR+1]. and fill it with -1. By doing so, the solution ensures each state is computed only once, significantly reducing the overall computational complexity.

C++
// C++ implementation to find Max OR of
// subsequence of size k using Memoization
#include <bits/stdc++.h>
using namespace std;

// Helper function with memoization
int maxOrHelper(vector<int>& arr, int n, int k, 
                 int index, int currOR, int currSize, 
                 vector<vector<vector<int>>>& memo) {

    // If we have selected k elements, return 
    // the current OR value
    if (currSize == k) {
        return currOR;
    }

    // If we have exhausted all elements
    if (index == n) {
        return 0;
    }

    // Check if the result is already computed
    if (memo[index][currSize][currOR] != -1) {
        return memo[index][currSize][currOR];
    }

    // Include the current element and recurse
    int include = maxOrHelper(arr, n, k, index + 1, 
                      currOR | arr[index], currSize + 1, memo);

    // Skip the current element and recurse
    int exclude = maxOrHelper(arr, n, k, index + 1, 
                              currOR, currSize, memo);

    // Store the result in the memoization table
    memo[index][currSize][currOR] = max(include, exclude);

    return memo[index][currSize][currOR];
}

int MaxOrK(vector<int>& arr, int k) {
    int n = arr.size();
    
    // Create a memoization table with dimensions [n][k+1]
    // [maximum possible OR value]
    int maxPossibleOR = 0;
    
    for (int num : arr) {
        maxPossibleOR |= num;
    }

    // Create a 3D memo table, initializing all values 
    // as -1
    vector<vector<vector<int>>> memo(n + 1, 
                                vector<vector<int>>(k + 1, 
                                vector<int>(maxPossibleOR + 1, -1)));

    return maxOrHelper(arr, n, k, 0, 0, 0, memo);
}

int main() {
  
    vector<int> arr = {2, 5, 3, 6, 11, 13};
    int k = 3;
    cout << MaxOrK(arr, k) << endl;
    return 0;
}
Java
// Java implementation to find Max OR of
// subsequence of size k using Memoization
import java.util.*;

class GfG {

    // Helper function with memoization
    static int maxOrHelper(List<Integer> arr, int n, int k, 
                           int index, int currOR, int currSize, 
                           int[][][] memo) {

        // If we have selected k elements, return 
        // the current OR value
        if (currSize == k) {
            return currOR;
        }

        // If we have exhausted all elements
        if (index == n) {
            return 0;
        }

        // Check if the result is already computed
        if (memo[index][currSize][currOR] != -1) {
            return memo[index][currSize][currOR];
        }

        // Include the current element and recurse
        int include = maxOrHelper(arr, n, k, index + 1, 
                                  currOR | arr.get(index), 
                                  currSize + 1, memo);

        // Skip the current element and recurse
        int exclude = maxOrHelper(arr, n, k, index + 1, 
                                  currOR, currSize, memo);

        // Store the result in the memoization table
        memo[index][currSize][currOR] = Math.max(include, exclude);

        return memo[index][currSize][currOR];
    }

    static int MaxOrK(List<Integer> arr, int k) {
        int n = arr.size();
        
        // Create a memoization table with dimensions [n][k+1]
        // [maximum possible OR value]
        int maxPossibleOR = 0;
        
        for (int num : arr) {
            maxPossibleOR |= num;
        }

        // Create a 3D memo table, initializing all values 
        // as -1
        int[][][] memo = new int[n + 1][k + 1][maxPossibleOR + 1];
        
        // Initialize the memo table with -1
        for (int i = 0; i <= n; i++) {
            for (int j = 0; j <= k; j++) {
                Arrays.fill(memo[i][j], -1);
            }
        }

        return maxOrHelper(arr, n, k, 0, 0, 0, memo);
    }

    public static void main(String[] args) {
      
        List<Integer> arr = Arrays.asList(2, 5, 3, 6, 11, 13);
        int k = 3;
        System.out.println(MaxOrK(arr, k));
    }
}
Python
# Python implementation to find Max OR of
# subsequence of size k using Memoization

# Helper function with memoization
def maxOrHelper(arr, n, k, index, currOR, currSize, memo):
  
    # If we have selected k elements, 
    # return the current OR value
    if currSize == k:
        return currOR

    # If we have exhausted all elements
    if index == n:
        return 0

    # Check if the result is already computed
    if memo[index][currSize][currOR] != -1:
        return memo[index][currSize][currOR]

    # Include the current element and recurse
    include = maxOrHelper(arr, n, k, index + 1, \
                  currOR | arr[index], currSize + 1, memo)

    # Skip the current element and recurse
    exclude = maxOrHelper(arr, n, k, \
                         index + 1, currOR, currSize, memo)

    # Store the result in the memoization table
    memo[index][currSize][currOR] = max(include, exclude)

    return memo[index][currSize][currOR]

def MaxOrK(arr, k):
    n = len(arr)
    
    # Create a memoization table with dimensions [n][k+1]
    # [maximum possible OR value]
    maxPossibleOR = 0
    
    for num in arr:
        maxPossibleOR |= num

    # Create a 3D memo table, initializing all values 
    # as -1
    memo = [[[ -1 for i in range(maxPossibleOR + 1)] \
              for i in range(k + 1)] for i in range(n + 1)]

    return maxOrHelper(arr, n, k, 0, 0, 0, memo)

if __name__ == "__main__":

    arr = [2, 5, 3, 6, 11, 13]
    k = 3
    print(MaxOrK(arr, k))
C#
// C# implementation to find Max OR of
// subsequence of size k using Memoization
using System;
using System.Collections.Generic;

class GfG {

    // Helper function with memoization
    static int MaxOrHelper(List<int> arr, int n, int k, 
                           int index, int currOR, int currSize, 
                           int[,,] memo) {

        // If we have selected k elements, return 
        // the current OR value
        if (currSize == k) {
            return currOR;
        }

        // If we have exhausted all elements
        if (index == n) {
            return 0;
        }

        // Check if the result is already computed
        if (memo[index, currSize, currOR] != -1) {
            return memo[index, currSize, currOR];
        }

        // Include the current element and recurse
        int include = MaxOrHelper(arr, n, k, index + 1, 
                                  currOR | arr[index],
                                  currSize + 1, memo);

        // Skip the current element and recurse
        int exclude = MaxOrHelper(arr, n, k, index + 1, 
                                  currOR, currSize, memo);

        // Store the result in the memoization table
        memo[index, currSize, currOR] = Math.Max(include, exclude);

        return memo[index, currSize, currOR];
    }

    static int MaxOrK(List<int> arr, int k) {
        int n = arr.Count;
        
        // Create a memoization table with dimensions [n][k+1]
        // [maximum possible OR value]
        int maxPossibleOR = 0;
        
        foreach (int num in arr) {
            maxPossibleOR |= num;
        }

        // Create a 3D memo table, initializing all values 
        // as -1
        int[,,] memo = new int[n + 1, k + 1, maxPossibleOR + 1];
        
        // Initialize the memo table with -1
        for (int i = 0; i <= n; i++) {
            for (int j = 0; j <= k; j++) {
                for (int l = 0; l <= maxPossibleOR; l++) {
                    memo[i, j, l] = -1;
                }
            }
        }

        return MaxOrHelper(arr, n, k, 0, 0, 0, memo);
    }

    static void Main() {
      
        List<int> arr = new List<int> { 2, 5, 3, 6, 11, 13 };
        int k = 3;
        Console.WriteLine(MaxOrK(arr, k));
    }
}
JavaScript
// Javascript implementation to find Max OR of
// subsequence of size k using Memoization

// Helper function with memoization
function maxOrHelper(arr, n, k, index, currOR, 
                               currSize, memo) {

    // If we have selected k elements, 
    // return the current OR value
    if (currSize === k) {
        return currOR;
    }

    // If we have exhausted all elements
    if (index === n) {
        return 0;
    }

    // Check if the result is already computed
    if (memo[index][currSize][currOR] !== -1) {
        return memo[index][currSize][currOR];
    }

    // Include the current element and recurse
    let include = maxOrHelper(arr, n, k, index + 1, 
                  currOR | arr[index], currSize + 1, memo);

    // Skip the current element and recurse
    let exclude = maxOrHelper(arr, n, k, 
                   index + 1, currOR, currSize, memo);

    // Store the result in the memoization table
    memo[index][currSize][currOR] = Math.max(include, exclude);

    return memo[index][currSize][currOR];
}

function MaxOrK(arr, k) {
    let n = arr.length;

    // Create a memoization table with dimensions [n][k+1]
    // [maximum possible OR value]
    let maxPossibleOR = 0;

    for (let num of arr) {
        maxPossibleOR |= num;
    }

    // Create a 3D memo table, initializing all values
    // as -1
    let memo = Array.from({ length: n + 1 }, () =>
        Array.from({ length: k + 1 }, () =>
            Array(maxPossibleOR + 1).fill(-1)
        )
    );

    return maxOrHelper(arr, n, k, 0, 0, 0, memo);
}

let arr = [2, 5, 3, 6, 11, 13];
let k = 3;
console.log(MaxOrK(arr, k));

Output
15

Related article:


Next Article

Similar Reads