The Number of Beautiful Subsets

Updated on 15 July, 2025
The Number of Beautiful Subsets header image

Problem Statement

The task is to determine the number of non-empty beautiful subsets of a given array nums of positive integers. A subset of nums is termed as beautiful if no two integers in this subset have an absolute difference equal to a given positive integer k. Each subset is derived by possibly removing zero or more elements from the array. The uniqueness of each subset is determined by the indices of the elements removed to form that subset. The problem requires calculating how many such beautiful subsets can be formed.

Examples

Example 1

Input:

nums = [2,4,6], k = 2

Output:

4

Explanation:

The beautiful subsets of the array nums are: [2], [4], [6], [2, 6].
It can be proved that there are only 4 beautiful subsets in the array [2,4,6].

Example 2

Input:

nums = [1], k = 1

Output:

1

Explanation:

The beautiful subset of the array nums is [1].
It can be proved that there is only 1 beautiful subset in the array [1].

Constraints

  • 1 <= nums.length <= 18
  • 1 <= nums[i], k <= 1000

Approach and Intuition

To solve this problem, consider the following steps and insights derived from the example provided:

Key Steps:

  1. Understand Subset Formation: Recognize that from an array of size n, the total number of subsets including the empty set is 2^n. For n integers, each has two choices: to be included or excluded from a subset.

  2. Subsets Compatibility: Each subset must be checked to ensure that no two integers within it have an absolute difference of k. To efficiently compare, consider the maximum allowable size of nums, which is 18. This manageable size might suggest employing a brute-force approach using bit masking or dynamic programming.

  3. Bit Mask Representation: Given the manageable scale (up to 2^18 subsets), consider using bit masks to represent subsets. Each bit in an integer up to 2^n could represent whether a corresponding element in nums is included (bit = 1) or not (bit = 0).

  4. Validation of Each Subset: For each subset represented by a bit mask, iterate through its elements (using the bits in the mask) and check for any two elements that contradict the "beautiful" condition (having an absolute difference of k). If such a pair is found, the subset is not beautiful.

  5. Counting Beautiful Subsets: Initialize a counter at zero. For each valid (beautiful) subset encountered, increment this counter. Finally, exclude the empty set if included by decreasing the counter by one if no difference dispute is found with an empty set.

Intuition:

  • The challenge hinges less on subset generation and more on efficiently validating the "beautiful" condition for potentially large numbers of subsets.
  • Since the maximum array size is limited to 18 elements, a computational approach involving all subsets is feasible.
  • The key computational task is to efficiently verify each subset for conflicting pairs, leveraging absolute differences and quick lookup/data access structures.

This approach is expected to efficiently solve the problem within the given constraint limits.

Solutions

  • C++
cpp
class Solution {
public:
    int countBeautifulSubsets(vector<int>& elements, int d) {
        int result = 1;
        map<int, map<int, int>> groupFreq;
    
        // Fill frequency map with mod groupings
        for (int& elem : elements) {
            groupFreq[elem % d][elem]++;
        }
    
        // Process each mod group
        for (auto& group : groupFreq) {
            int lastNum = -d, beforeLast, last = 1, thisCount;
    
            // Go through each element in the mod group
            for (auto& [element, frequency] : group.second) {
                // Cases without current element
                int exclude = last;
    
                // Cases with inclusion of the current element
                int include;
                if (element - lastNum == d) {
                    include = ((1 << frequency) - 1) * beforeLast;
                } else {
                    include = ((1 << frequency) - 1) * last;
                }
    
                // Total cases for this element
                thisCount = exclude + include;
                beforeLast = last;
                last = thisCount;
                lastNum = element;
            }
            result *= thisCount;
        }
        return result - 1;
    }
};

This C++ solution focuses on counting the number of beautiful subsets from a given set of integers, where a subset is considered beautiful if the difference between any two of its elements is a multiple of a specified integer 'd'. Here’s a detailed breakdown of how the solution is implemented:

  1. Initialize a result variable as 1 to handle edge cases where there might be no such subsets.

  2. Utilize a two-level map groupFreq to store the frequency of integers based on their modulo with 'd'. This allows grouping of numbers which when divided by 'd' leave the same remainder.

  3. Loop through the given elements vector, fill groupFreq with frequencies of each element based on their modulo result with 'd’.

  4. Iterate through each group in groupFreq. For each group, maintain three variables lastNum, beforeLast, and last representing the last number, the result before the last computed result, and the last computed result, respectively.

  5. For each element in a group, compute the cases where the element is excluded (exclude) and where it is included (include). The inclusion is further differentiated based on whether the current element and the last element processed are spaced by 'd' or not.

  6. Combine the include and exclude cases to get the total cases thisCount for this element.

  7. Accumulate the result by multiplying it with thisCount for each group.

  8. Finally, subtract 1 from the result to exclude the empty subset.

The solution takes advantage of bitwise operations and efficient use of dynamic programming to combine cases, efficiently handling subsets and their combinations with respect to the given constraints of modulo operation and difference being a multiple of 'd'.

  • Java
java
class Solution {
    
    public int calculateBeautifulSubsets(int[] arr, int divisor) {
        int countResult = 1;
        Map<Integer, Map<Integer, Integer>> groupMap = new TreeMap<>();
    
        // Count frequencies by dividing
        for (int value : arr) {
            Map<Integer, Integer> countMap = groupMap.getOrDefault(
                value % divisor,
                new TreeMap<>()
            );
            countMap.put(value, countMap.getOrDefault(value, 0) + 1);
            groupMap.put(value % divisor, countMap);
        }
    
        // Process each remainder
        for (Map.Entry<
            Integer,
            Map<Integer, Integer>
        > group : groupMap.entrySet()) {
            int lastNum = -divisor, twoBack = 0, oneBack = 1, present = 1;
    
            // Process each number in this group
            for (Map.Entry<Integer, Integer> count : group
                .getValue()
                .entrySet()) {
                int number = count.getKey();
                int frequency = count.getValue();
                // Count excluding current number
                int exclude = oneBack;
    
                // Count including current number
                int include;
                if (number - lastNum == divisor) {
                    include = ((1 << frequency) - 1) * twoBack;
                } else {
                    include = ((1 << frequency) - 1) * oneBack;
                }
    
                present = exclude + include; // Accumulate count
                twoBack = oneBack;
                oneBack = present;
                lastNum = number;
            }
            countResult *= present;
        }
        return countResult - 1;
    }
}

This Java program defines a method calculateBeautifulSubsets to compute the number of subsets that meet specific divisibility criteria in relation to a given divisor. Here's a breakdown of how the solution works:

  • The method accepts an integer array arr and an integer divisor as parameters.
  • A TreeMap named groupMap is utilized to categorize numbers based on their remainders when divided by the divisor. Each distinct remainder holds another TreeMap that counts occurrences of each number producing that remainder.
  • Frequency of each number is calculated by looping over the arr, examining the remainder of each value when divided by divisor, and updating the frequency counts in the appropriate inner TreeMap.
  • For each unique remainder group, the method processes potentially beautiful subsets. The current, one step back, and two steps back count results are tracked as present, oneBack, and twoBack, respectively.
  • For each entry in a remainder group, if the difference between the current number and the last processed number equals the divisor, the calculation considers the subsequences that can be formed by including the current number (combining its frequency combinations with twoBack subsequences). Otherwise, it combines with oneBack.
  • At the end of processing each group, the cumulative count of beautiful subsets for that group (present) is multiplied with the count from previous groups stored in countResult.
  • The final result is then adjusted by subtracting 1 to exclude the empty subset, ensuring the returned result accurately reflects the count of non-empty beautiful subsets.

This efficient method leverages combinatorial properties and organized data structuring to ensure that the problem of counting beautiful subsets depending on divisibility conditions is handled accurately and efficiently.

  • Python
python
class Solution:
    def countBeautifulSubsets(self, arr: List[int], diff: int) -> int:
        total_subsets = 1
        mod_map = defaultdict(dict)
    
        # Create frequency map wrt remainder when divided by diff
        for element in arr:
            remainder = element % diff
            if element not in mod_map[remainder]:
                mod_map[remainder][element] = 0
            mod_map[remainder][element] += 1
    
        # Evaluate each modulo class
        for remainder_group in mod_map.values():
            previous, current_count, prev_count1, prev_count2 = -diff, 1, 1, 0
    
            # Sort and loop through each unique number in modulus group
            for number, count in sorted(remainder_group.items()):
                # If we skip this number
                skip = prev_count1
    
                # Take all possible subsets including this number
                if number - previous == diff:
                    include = ((1 << count) - 1) * prev_count2
                else:
                    include = ((1 << count) - 1) * prev_count1
    
                current_count = skip + include
                prev_count2, prev_count1 = prev_count1, current_count
                previous = number
                
            total_subsets *= current_count
            
        # Subtract empty set
        return total_subsets - 1

This Python solution resolves the problem of counting the number of beautiful subsets within an array, where a subset is considered beautiful if the difference between two consecutive elements is a specific integer (diff). The implemented method, countBeautifulSubsets, employs a dynamic programming approach with combinations of bitwise operations to compute the desired count.

  • A dictionary mod_map maps each element to another dictionary tracking the frequency of that element modulo diff.
  • For each modulo diff group in mod_map, iterate through the sorted group elements to compute possible subsets:
    • Use the difference factoring diff to manage inclusion or exclusion conditions of elements thereby controlling beautiful subset formation.
    • A dynamic update of current subset counts depends on whether the current and previous elements satiate the difference condition.
    • Subset count updates consider both the scenarios of skipping the current number or including it in subsets with respect to earlier counted subsets.
  • Finally, calculate total beautiful subsets by multiplying counts from each modulo class. The empty set is subtracted as it's not considered a subset.

The solution effectively manages subset combinations via a mix of sorting, binary shifts for subset calculations, and dynamic programming, economizing on computing resources while handling potential large input scales.

Comments

No comments yet.