Open In App

Maximum subsequence sum from a given array which is a perfect square

Improve
Improve
Like Article
Like
Save
Share
Report

Given an array arr[], the task is to find the sum of a subsequence that forms a perfect square. If there are multiple subsequences having a sum equal to a perfect square, print the maximum sum.
Explanation: 
 

Input: arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9} 
Output: 36 
Explanation: 
Maximum possible sum which is a perfect square that can be obtained from the array is 36 obtained from the subsequence {1, 5, 6, 7, 8, 9}.
Input: arr[] = {9, 10} 
Output:
 

Naive Approach: Generate all the possible subsequences of a given array and for each subsequence, check if its sum is a Perfect Square. If such a sum is found, update the maximum sum. Finally, print the maximum sum obtained. 
Time Complexity: O(N * 2N
Auxiliary Space: O(N)
 

Efficient Approach: 
The above approach can be optimized by using Dynamic Programming approach. 
Follow the steps given below: 
 

  • Calculate the sum of the array.
  • Iterate k in the range [?sum, 0] and check if any subsequence exists with that sum k2. For every k, follow the steps below: 
    • Initialize boolean matrix subset[][] of dimensions N * sum, where sum denotes the current value of k2.
    • subset[i][j] denotes whether a subsequence of size i with sum j exists or not.
    • Initialize first column and first row as true and false respectively of subset[][].
    • Run two nested loops, outer from i in the range [1, N] and inner j in the range [1, sum]to fill the subset[][] matrix in bottom up manner based on the following conditions: 
      • if (j < arr[i – 1]), then subset[i][j] = subset[i – 1][j]
      • if (j >= arr[i – 1]), then subset[i][j] = subset[i – 1][j] || subset[i – 1][j – arr[i – 1]]
    • Finally, return the subset[n][sum].
  • The first k for which subset[n][k] is true, gives the required maximum possible subsequence sum k2.

Below is the implementation of the above approach:
 

C++




// C++ Program to implement
// the above approach
#include <bits/stdc++.h>
using namespace std;
bool isSubsetSum(int arr[], int n, int sum)
{
    bool subset[n + 1][sum + 1];
 
    // If sum is 0, then answer is true
    for (int i = 0; i <= n; i++)
        subset[i][0] = true;
 
    // If sum is not 0 and arr[] is empty,
    // then answer is false
    for (int i = 1; i <= sum; i++)
        subset[0][i] = false;
 
    // Fill the subset table in bottom up manner
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= sum; j++) {
 
            if (j < arr[i - 1])
                subset[i][j] = subset[i - 1][j];
 
            if (j >= arr[i - 1])
                subset[i][j]
                    = subset[i - 1][j]
                      || subset[i - 1][j - arr[i - 1]];
        }
    }
 
    return subset[n][sum];
}
// Function to find the sum
int findSum(int* arr, int n)
{
    int sum = 0;
    // Find sum of all values
    for (int i = 0; i < n; i++) {
        sum += arr[i];
    }
 
    int val = sqrt(sum);
 
    for (int i = val; i >= 0; i--) {
        if (isSubsetSum(arr, n, i * i)) {
            // return the value;
            return i * i;
        }
    }
 
    return 0;
}
 
// Driver Code
int main()
{
    int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
    int n = sizeof(arr) / sizeof(arr[0]);
    cout << findSum(arr, n) << endl;
    return 0;
}


Java




// Java program to implement
// the above approach
import java.util.*;
 
class GFG{
 
static boolean isSubsetSum(int arr[],
                           int n, int sum)
{
    boolean[][] subset = new boolean[n + 1][sum + 1];
 
    // If sum is 0, then answer is true
    for(int i = 0; i <= n; i++)
        subset[i][0] = true;
 
    // If sum is not 0 and arr[] is empty,
    // then answer is false
    for(int i = 1; i <= sum; i++)
        subset[0][i] = false;
 
    // Fill the subset table in bottom up manner
    for(int i = 1; i <= n; i++)
    {
        for(int j = 1; j <= sum; j++)
        {
            if (j < arr[i - 1])
                subset[i][j] = subset[i - 1][j];
 
            if (j >= arr[i - 1])
                subset[i][j] = subset[i - 1][j] ||
                subset[i - 1][j - arr[i - 1]];
        }
    }
    return subset[n][sum];
}
 
// Function to find the sum
static int findSum(int[] arr, int n)
{
    int sum = 0;
     
    // Find sum of all values
    for(int i = 0; i < n; i++)
    {
        sum += arr[i];
    }
 
    int val = (int)Math.sqrt(sum);
 
    for(int i = val; i >= 0; i--)
    {
        if (isSubsetSum(arr, n, i * i))
        {
             
            // return the value;
            return i * i;
        }
    }
    return 0;
}
 
// Driver code
public static void main(String[] args)
{
    int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
    int n = arr.length;
     
    System.out.println(findSum(arr, n));
}
}
 
// This code is contributed by offbeat


Python3




# Python3 program to implement
# the above approach
import math
 
def isSubsetSum(arr, n, sum):
     
    subset = [ [ True for x in range(sum + 1) ]
                      for y in range(n + 1) ]
 
    # If sum is 0, then answer is true
    for i in range(n + 1):
        subset[i][0] = True
 
    # If sum is not 0 and arr[] is empty,
    # then answer is false
    for i in range(1, sum + 1):
        subset[0][i] = False
 
    # Fill the subset table in bottom up manner
    for i in range(1, n + 1):
        for j in range(1, sum + 1):
 
            if (j < arr[i - 1]):
                subset[i][j] = subset[i - 1][j]
 
            if (j >= arr[i - 1]):
                subset[i][j] = (subset[i - 1][j] or
                                subset[i - 1][j -
                                   arr[i - 1]])
                                    
    return subset[n][sum]
 
# Function to find the sum
def findSum(arr, n):
     
    sum = 0
     
    # Find sum of all values
    for i in range(n):
        sum += arr[i]
 
    val = int(math.sqrt(sum))
 
    for i in range(val, -1, -1):
        if (isSubsetSum(arr, n, i * i)):
             
            # Return the value;
            return i * i
             
    return 0
 
# Driver Code
if __name__ == "__main__":
 
    arr = [ 1, 2, 3, 4, 5, 6, 7, 8, 9]
    n = len(arr)
     
    print(findSum(arr, n))
 
# This code is contributed by chitranayal


C#




// C# program to implement
// the above approach
using System;
 
class GFG{
 
static bool isSubsetSum(int []arr,
                        int n, int sum)
{
    bool[,] subset = new bool[n + 1, sum + 1];
 
    // If sum is 0, then answer is true
    for(int i = 0; i <= n; i++)
        subset[i, 0] = true;
 
    // If sum is not 0 and []arr is empty,
    // then answer is false
    for(int i = 1; i <= sum; i++)
        subset[0, i] = false;
 
    // Fill the subset table in bottom up manner
    for(int i = 1; i <= n; i++)
    {
        for(int j = 1; j <= sum; j++)
        {
            if (j < arr[i - 1])
                subset[i, j] = subset[i - 1, j];
 
            if (j >= arr[i - 1])
                subset[i, j] = subset[i - 1, j] ||
                subset[i - 1, j - arr[i - 1]];
        }
    }
    return subset[n, sum];
}
 
// Function to find the sum
static int findSum(int[] arr, int n)
{
    int sum = 0;
     
    // Find sum of all values
    for(int i = 0; i < n; i++)
    {
        sum += arr[i];
    }
 
    int val = (int)Math.Sqrt(sum);
 
    for(int i = val; i >= 0; i--)
    {
        if (isSubsetSum(arr, n, i * i))
        {
             
            // return the value;
            return i * i;
        }
    }
    return 0;
}
 
// Driver code
public static void Main(String[] args)
{
    int []arr = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
    int n = arr.Length;
     
    Console.WriteLine(findSum(arr, n));
}
}
 
// This code is contributed by Rohit_ranjan


Javascript




<script>
 
// JavaScript program to implement
// the above approach
 
function isSubsetSum(arr, n, sum)
{
    let subset = new Array(n + 1);
    for (var i = 0; i < subset.length; i++) {
    subset[i] = new Array(2);
    }
   
    // If sum is 0, then answer is true
    for(let i = 0; i <= n; i++)
        subset[i][0] = true;
   
    // If sum is not 0 and arr[] is empty,
    // then answer is false
    for(let i = 1; i <= sum; i++)
        subset[0][i] = false;
   
    // Fill the subset table in bottom up manner
    for(let i = 1; i <= n; i++)
    {
        for(let j = 1; j <= sum; j++)
        {
            if (j < arr[i - 1])
                subset[i][j] = subset[i - 1][j];
   
            if (j >= arr[i - 1])
                subset[i][j] = subset[i - 1][j] ||
                subset[i - 1][j - arr[i - 1]];
        }
    }
    return subset[n][sum];
}
   
// Function to find the sum
function findSum(arr, n)
{
    let sum = 0;
       
    // Find sum of all values
    for(let i = 0; i < n; i++)
    {
        sum += arr[i];
    }
   
    let val = Math.floor(Math.sqrt(sum));
   
    for(let i = val; i >= 0; i--)
    {
        if (isSubsetSum(arr, n, i * i))
        {
               
            // return the value;
            return i * i;
        }
    }
    return 0;
}
 
    // Driver Code
         
    let arr = [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ];
    let n = arr.length;
       
    document.write(findSum(arr, n));
 
</script>


Output

36

Time Complexity: O(N * SUM) 
Auxiliary Space: O(N * SUM)
 

Efficient approach : Space optimization

In previous approach the current value subset[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 array subset of size sum+1 and initialize it with false.
  • Set a base case and initialize subset[0] = True.
  • Now iterate over subproblems by the help of nested loop and get the current value from previous computations.
  • At last return the final answer stored in subset[sum].

Implementation:

C++




// C++ Program to implement
// the above approach
 
#include <bits/stdc++.h>
using namespace std;
 
bool isSubsetSum(int arr[], int n, int sum)
{
    bool subset[sum + 1];
    memset(subset, false, sizeof(subset));
    // If sum is 0, then answer is true
    subset[0] = true;
     
    // iterative over subproblems to get the
    // current value from previous computations
    for (int i = 0; i < n; i++) {
        for (int j = sum; j >= arr[i]; j--) {
            subset[j] = subset[j] || subset[j - arr[i]];
        }
    }
     
    // return final answer
    return subset[sum];
}
 
// Function to find the sum
int findSum(int* arr, int n)
{
    int sum = 0;
     
    // Find sum of all values
    for (int i = 0; i < n; i++) {
        sum += arr[i];
    }
 
    int val = sqrt(sum);
 
    for (int i = val; i >= 0; i--) {
        if (isSubsetSum(arr, n, i * i)) {
             
            // return the value;
            return i * i;
        }
    }
 
    return 0;
}
 
// Driver Code
int main()
{
    int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
    int n = sizeof(arr) / sizeof(arr[0]);
     
    // function call
    cout << findSum(arr, n) << endl;
    return 0;
}
 
// this code is contributed by bhardwajji


Java




// Java program to implement
// the above approach
 
import java.io.*;
import java.util.*;
 
class GFG {
  static boolean isSubsetSum(int[] arr, int n, int sum)
{
    boolean[] subset = new boolean[sum + 1];
    Arrays.fill(subset, false);
 
    // If sum is 0, then answer is true
    subset[0] = true;
 
    // iterative over subproblems to get the
    // current value from previous computations
    for (int i = 0; i < n; i++) {
        for (int j = sum; j >= arr[i]; j--) {
            subset[j] = subset[j] || subset[j - arr[i]];
        }
    }
 
    // return final answer
    return subset[sum];
}
 
// Function to find the sum
static int findSum(int[] arr, int n)
{
    int sum = 0;
 
    // Find sum of all values
    for (int i = 0; i < n; i++) {
        sum += arr[i];
    }
 
    int val = (int) Math.sqrt(sum);
 
    for (int i = val; i >= 0; i--) {
        if (isSubsetSum(arr, n, i * i)) {
 
            // return the value;
            return i * i;
        }
    }
 
    return 0;
}
 
// Driver Code
public static void main(String[] args)
{
    int[] arr = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
    int n = arr.length;
 
    // function call
    System.out.println(findSum(arr, n));
}
}


Python3




import math
 
# Function to check if a subset with
# given sum exists in the array
def isSubsetSum(arr, n, target):
   
    # Initialize a boolean array
    # subset of size target+1 and
    # fill it with False
    subset = [False] * (target + 1)
     
    # Set subset[0] to True as a subset
    # with sum 0 always exists
    subset[0] = True
 
    # Iterate through all elements
    # in the array
    for i in range(n):
       
        # Iterate backwards through the
        # subset array starting from target
        # and going down to arr[i]
        # This is done to avoid recomputing
        # subsets that have already been checked
        for j in range(target, arr[i] - 1, -1):
           
            # If subset[j-arr[i]] is True, then
            # a subset with sum j-arr[i] exists
            # Therefore, a subset with sum j can
            # be formed by adding arr[i] to this subset
            subset[j] = subset[j] or subset[j - arr[i]]
 
    # Return True if a subset with the
    # target sum exists, else False
    return subset[target]
 
# Function to find the largest perfect square
# less than or equal to the sum of all elements
# in the array
def findSum(arr, n):
   
    # Find the sum of all elements
    # in the array
    total_sum = sum(arr)
     
    # Find the square root of the sum of all
    # elements and cast it to an integer
    val = int(math.sqrt(total_sum))
 
    # Iterate backwards from the square
    # root of the sum of all elements
    for i in range(val, -1, -1):
       
        # If a subset with sum i*i exists,
        # return i*i
        if isSubsetSum(arr, n, i * i):
            return i * i
 
    # If no perfect square is found,
    # return 0
    return 0
 
# Driver Code
if __name__ == "__main__":
   
    # Initialize an array of integers
    arr = [1, 2, 3, 4, 5, 6, 7, 8, 9]
     
    # Find the length of the array
    n = len(arr)
     
    # Call the findSum function and
    # print the result
    print(findSum(arr, n))


C#




using System;
 
public class GFG {
 
  static bool isSubsetSum(int[] arr, int n, int sum)
  {
    bool[] subset = new bool[sum + 1];
    Array.Fill(subset, false);
 
    // If sum is 0, then answer is true
    subset[0] = true;
 
    // iterative over subproblems to get the
    // current value from previous computations
    for (int i = 0; i < n; i++) {
      for (int j = sum; j >= arr[i]; j--) {
        subset[j] = subset[j] || subset[j - arr[i]];
      }
    }
 
    // return final answer
    return subset[sum];
  }
 
  static int findSum(int[] arr, int n)
  {
    int sum = 0;
 
    // Find sum of all values
    for (int i = 0; i < n; i++) {
      sum += arr[i];
    }
 
    int val = (int)Math.Sqrt(sum);
 
    for (int i = val; i >= 0; i--) {
      if (isSubsetSum(arr, n, i * i)) {
 
        // return the value;
        return i * i;
      }
    }
 
    return 0;
  }
 
  public static void Main()
  {
    int[] arr = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
    int n = arr.Length;
 
    // function call
    Console.WriteLine(findSum(arr, n));
  }
}


Javascript




function isSubsetSum(arr, n, sum) {
    const subset = new Array(sum + 1).fill(false);
    // If sum is 0, then the answer is true
    subset[0] = true;
 
    // Iterate over subproblems to get the current value from previous computations
    for (let i = 0; i < n; i++) {
        for (let j = sum; j >= arr[i]; j--) {
            subset[j] = subset[j] || subset[j - arr[i]];
        }
    }
 
    // Return the final answer
    return subset[sum];
}
 
function findSum(arr, n) {
    let sum = 0;
 
    // Find the sum of all values
    for (let i = 0; i < n; i++) {
        sum += arr[i];
    }
 
    const val = Math.floor(Math.sqrt(sum));
 
    for (let i = val; i >= 0; i--) {
        if (isSubsetSum(arr, n, i * i)) {
            // Return the value
            return i * i;
        }
    }
 
    return 0;
}
 
// Driver Code
const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
const n = arr.length;
 
// Function call
console.log(findSum(arr, n));


Output

36

Time Complexity: O(N * SUM) 
Auxiliary Space: O(SUM)



Last Updated : 26 Oct, 2023
Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads