Open In App

Maximize Size of Subsets having Equal Values

Last Updated : 17 Jan, 2024
Improve
Improve
Like Article
Like
Save
Share
Report

Given array A[] of size N and integer M, ith element from N elements represents A[i]th type. Create M sets each of size X and consists of the same type of elements. Task for this problem is to maximize value of X.

Constraints:

  • 1 <= N <= 105
  • 1 <= A[i] <= 109
  • 1 <= M <= 109

Examples:

Input: A[] = {1, 5, 2, 1, 1, 1, 2, 5, 7, 2}, M = 4
Output: 2
Explanation: M = 4 sets are created and each set has assigned X = 2 elements.

  • first set will be {1, 1} (here first and fourth element are assigned)
  • second set will be {1, 1} (here fifth and sixth element are assigned)
  • third set will be {2, 2} (here third and seventh element are assigned)
  • fourth set will be {5, 5} (here second and eighth element are assigned)

so X = 2 is the answer.

Input: A[] = {5, 4, 3, 2, 1}, M = 2
Output: 1

Explanation: M = 2 sets are created and each set has assigned X = 1 element

  • first set will be {5} (here first element is assigned)
  • second set will be {4} (here second element is assigned)

so X = 1 is the answer

Approach: To solve the problem follow the below idea:

Binary Search can be used to solve this problem and the range of binary search will be 1 to 1e9. f(n) is monotonic function that represents whether M sets of size n can be formed or not. it is of the form TTTTTFFFFFF. we have to find when the last time function was true using Binary Search.

Below are the steps for the above approach:

  • Declare HashMap[] that stores frequency of each element of array A[].
  • Iterate over all elements in array A[] and fill the HashMap[].
  • Set low and high range of binary search.
  • ispos(mid) function used to check if M sets each of size mid can formed or not.
  • Run while loop till high and low are not equal.
  • In while loop find middle element and store it in mid variable.
  • Check if M sets each of size mid can be formed or not using ispos() function. If it is true then set low = mid else high = mid – 1.
  • After loop ends if ispos() true for high then return high else check if it is true for low then return low else return -1.

Below is the implementation of the above approach:

C++




// C++ code to implement the approach
#include <bits/stdc++.h>
using namespace std;
 
// Function to check if array can be distributed in M sets
// with each set has mid elements
bool ispos(int mid, unordered_map<int, int>& HashMap, int M)
{
    // number of sets possible
    int numberOfSetsPosofSizeMid = 0;
 
    // iterating in hashmap
    for (auto& e : HashMap) {
 
        // e.second is frequency of one of numbers in array
        // it can be divided in e.second / mid sets
        numberOfSetsPosofSizeMid += (e.second / mid);
    }
 
    // if number of sets of size mid are more
    // than required number of distributions than
    // return true else return false
    return numberOfSetsPosofSizeMid >= M;
}
 
// Function to find Maximize the equal number of
// elements distributed in M sets of same type
int findMinOp(int A[], int N, int M)
{
 
    // declaring frequencey HashMap
    unordered_map<int, int> HashMap;
 
    // iterating over all N elements and filling
    // the hashmap
    for (int i = 0; i < N; i++) {
        HashMap[A[i]]++;
    }
 
    // Range of binary search
    int low = 1, high = 1e9;
 
    // Running loop till high
    // is not equal to low
    while (high - low > 1) {
 
        // mid is average of low and high
        int mid = (low + high) / 2;
 
        // Checking test function
        if (ispos(mid, HashMap, M)) {
            low = mid;
        }
        else {
            high = mid - 1;
        }
    }
 
    // Checking whether high can be answer
    if (ispos(high, HashMap, M))
        return high;
 
    // If not then it is low
    else if (ispos(low, HashMap, M))
        return low;
    else
        return -1;
}
 
// Driver Code
int32_t main()
{
 
    // Input 1
    int N = 10, M = 4;
    int A[] = { 1, 5, 2, 1, 1, 1, 2, 5, 7, 2 };
 
    // Function Call
    cout << findMinOp(A, N, M) << endl;
 
    // Input 2
    int N1 = 5, M1 = 2;
    int A1[] = { 5, 4, 3, 2, 1 };
 
    // Function Call
    cout << findMinOp(A1, N1, M1) << endl;
 
    return 0;
}


Java




import java.util.HashMap;
import java.util.Map;
 
public class Main {
 
    // Function to check if array can be distributed in M
    // sets with each set having mid elements
    static boolean
    isPos(int mid, Map<Integer, Integer> hashMap, int M)
    {
        // Number of sets possible
        int numberOfSetsPosOfSizeMid = 0;
 
        // Iterating in HashMap
        for (Map.Entry<Integer, Integer> entry :
             hashMap.entrySet()) {
            // entry.getValue() is the frequency of one of
            // the numbers in the array It can be divided
            // into entry.getValue() / mid sets
            numberOfSetsPosOfSizeMid
                += (entry.getValue() / mid);
        }
 
        // If the number of sets of size mid is greater than
        // or equal to the required number of distributions
        // Return true, else return false
        return numberOfSetsPosOfSizeMid >= M;
    }
 
    // Function to find maximize the equal number of
    // elements distributed in M sets of the same type
    static int findMinOp(int[] A, int N, int M)
    {
        // Declaring frequency HashMap
        Map<Integer, Integer> hashMap = new HashMap<>();
 
        // Iterating over all N elements and filling the
        // HashMap
        for (int i = 0; i < N; i++) {
            hashMap.put(A[i],
                        hashMap.getOrDefault(A[i], 0) + 1);
        }
 
        // Range of binary search
        int low = 1, high = (int)1e9;
 
        // Running loop until high is not equal to low
        while (high - low > 1) {
            // mid is the average of low and high
            int mid = (low + high) / 2;
 
            // Checking test function
            if (isPos(mid, hashMap, M)) {
                low = mid;
            }
            else {
                high = mid - 1;
            }
        }
 
        // Checking whether high can be the answer
        if (isPos(high, hashMap, M))
            return high;
        // If not, then it is low
        else if (isPos(low, hashMap, M))
            return low;
        else
            return -1;
    }
 
    // Driver Code
    public static void main(String[] args)
    {
        // Input 1
        int N = 10, M = 4;
        int[] A = { 1, 5, 2, 1, 1, 1, 2, 5, 7, 2 };
 
        // Function Call
        System.out.println(findMinOp(A, N, M));
 
        // Input 2
        int N1 = 5, M1 = 2;
        int[] A1 = { 5, 4, 3, 2, 1 };
 
        // Function Call
        System.out.println(findMinOp(A1, N1, M1));
    }
}


Python3




def is_pos(mid, hash_map, M):
    # Number of sets possible
    number_of_sets_pos_of_size_mid = 0
 
    # Iterating in hash_map
    for key, value in hash_map.items():
        # value is the frequency of one of the numbers in array
        # it can be divided into value // mid sets
        number_of_sets_pos_of_size_mid += value // mid
 
    # If the number of sets of size mid is more than the required number of distributions
    # then return True, else return False
    return number_of_sets_pos_of_size_mid >= M
 
 
def find_min_op(arr, N, M):
    # Declaring frequency hash_map
    hash_map = {}
 
    # Iterating over all N elements and filling the hash_map
    for num in arr:
        if num in hash_map:
            hash_map[num] += 1
        else:
            hash_map[num] = 1
 
    # Range of binary search
    low, high = 1, 10**9
 
    # Running loop until high is not equal to low
    while high - low > 1:
        # mid is the average of low and high
        mid = (low + high) // 2
 
        # Checking the test function
        if is_pos(mid, hash_map, M):
            low = mid
        else:
            high = mid - 1
 
    # Checking whether high can be the answer
    if is_pos(high, hash_map, M):
        return high
    # If not, then it is low
    elif is_pos(low, hash_map, M):
        return low
    else:
        return -1
 
 
# Driver Code
if __name__ == "__main__":
    # Input 1
    N = 10
    M = 4
    A = [1, 5, 2, 1, 1, 1, 2, 5, 7, 2]
 
    # Function Call
    print(find_min_op(A, N, M))
 
    # Input 2
    N1 = 5
    M1 = 2
    A1 = [5, 4, 3, 2, 1]
 
    # Function Call
    print(find_min_op(A1, N1, M1))


C#




// C# code to implement the approach
using System;
using System.Collections.Generic;
 
class GFG {
    // Function to check if array can be distributed in M sets
    // with each set having mid elements
    static bool IsPos(int mid, Dictionary<int, int> HashMap, int M) {
        // number of sets possible
        int numberOfSetsPosOfSizeMid = 0;
 
        // iterating in hashmap
        foreach (var e in HashMap) {
            // e.Value is frequency of one of numbers in array
            // it can be divided in e.Value / mid sets
            numberOfSetsPosOfSizeMid += (e.Value / mid);
        }
 
        // if number of sets of size mid are more
        // than required number of distributions, return true, else return false
        return numberOfSetsPosOfSizeMid >= M;
    }
 
    // Function to find Maximize the equal number of
    // elements distributed in M sets of the same type
    static int FindMinOp(int[] A, int N, int M) {
        // declaring frequency HashMap
        Dictionary<int, int> HashMap = new Dictionary<int, int>();
 
        // iterating over all N elements and filling the hashmap
        for (int i = 0; i < N; i++) {
            if (HashMap.ContainsKey(A[i])) {
                HashMap[A[i]]++;
            } else {
                HashMap.Add(A[i], 1);
            }
        }
 
        // Range of binary search
        int low = 1, high = (int)1e9;
 
        // Running loop till high
        // is not equal to low
        while (high - low > 1) {
            // mid is the average of low and high
            int mid = (low + high) / 2;
 
            // Checking test function
            if (IsPos(mid, HashMap, M)) {
                low = mid;
            } else {
                high = mid - 1;
            }
        }
 
        // Checking whether high can be the answer
        if (IsPos(high, HashMap, M)) {
            return high;
        }
        // If not then it is low
        else if (IsPos(low, HashMap, M)) {
            return low;
        } else {
            return -1;
        }
    }
 
    // Driver Code
    public static void Main (string[] args) {
        // Input 1
        int[] A = { 1, 5, 2, 1, 1, 1, 2, 5, 7, 2 };
        int N = 10, M = 4;
 
        // Function Call
        Console.WriteLine(FindMinOp(A, N, M));
 
        // Input 2
        int[] A1 = { 5, 4, 3, 2, 1 };
        int N1 = 5, M1 = 2;
 
        // Function Call
        Console.WriteLine(FindMinOp(A1, N1, M1));
    }
}


Javascript




// JavaScript Implementation
 
// Function to check if array can be distributed in M sets
// with each set has mid elements
function ispos(mid, HashMap, M) {
  // number of sets possible
  let numberOfSetsPosofSizeMid = 0;
 
  // iterating in hashmap
  for (let key in HashMap) {
    // e.second is frequency of one of numbers in array
    // it can be divided in e.second / mid sets
    numberOfSetsPosofSizeMid += Math.floor(HashMap[key] / mid);
  }
 
  // if number of sets of size mid are more
  // than required number of distributions than
  // return true else return false
  return numberOfSetsPosofSizeMid >= M;
}
 
// Function to find Maximize the equal number of
// elements distributed in M sets of same type
function findMinOp(A, N, M) {
  // declaring frequencey HashMap
  let HashMap = {};
 
  // iterating over all N elements and filling
  // the hashmap
  for (let i = 0; i < N; i++) {
    if (HashMap[A[i]]) {
      HashMap[A[i]]++;
    } else {
      HashMap[A[i]] = 1;
    }
  }
 
  // Range of binary search
  let low = 1, high = 1e9;
 
  // Running loop till high
  // is not equal to low
  while (high - low > 1) {
    // mid is average of low and high
    let mid = Math.floor((low + high) / 2);
 
    // Checking test function
    if (ispos(mid, HashMap, M)) {
      low = mid;
    } else {
      high = mid - 1;
    }
  }
 
  // Checking whether high can be answer
  if (ispos(high, HashMap, M)) {
    return high;
  }
  // If not then it is low
  else if (ispos(low, HashMap, M)) {
    return low;
  } else {
    return -1;
  }
}
 
// Driver Code
let N = 10, M = 4;
let A = [1, 5, 2, 1, 1, 1, 2, 5, 7, 2];
 
// Function Call
console.log(findMinOp(A, N, M));
 
let N1 = 5, M1 = 2;
let A1 = [5, 4, 3, 2, 1];
 
// Function Call
console.log(findMinOp(A1, N1, M1));
 
// This code is contributed by Sakshi


Output

2
1

Time Complexity: O(NlogN)
Auxiliary Space: O(1)



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads